11//! Contains the definition of the configuration to be generated
22
3- use std:: collections:: HashMap ;
3+ use std:: { collections:: HashMap , convert :: Infallible } ;
44
55use serde:: Serialize ;
66
7- use crate :: http:: config:: ProxyConfig ;
8-
97/// Represents the set of agents to be included in the AC configuration.
108#[ derive( Debug , Copy , Clone , PartialEq , clap:: ValueEnum ) ]
119pub enum AgentSet {
@@ -36,6 +34,46 @@ impl From<AgentSet> for HashMap<String, Agent> {
3634 }
3735}
3836
37+ /// Holds the proxy configuration.
38+ /// Cannot use [crate::http::config::ProxyConfig] directly due lack of support for defaults in clap.
39+ /// See <https://github.com/clap-rs/clap/issues/4746> for details.
40+ #[ derive( Debug , Default , Clone , PartialEq , Serialize , clap:: Args ) ]
41+ pub struct ProxyConfig {
42+ #[ serde( skip_serializing_if = "is_none_or_empty_string" , rename = "url" ) ]
43+ #[ arg( long, required = false ) ]
44+ pub proxy_url : Option < String > ,
45+
46+ #[ serde(
47+ skip_serializing_if = "is_none_or_empty_string" ,
48+ rename = "ca_bundle_dir"
49+ ) ]
50+ #[ arg( long, required = false ) ]
51+ pub proxy_ca_bundle_dir : Option < String > ,
52+
53+ #[ serde(
54+ skip_serializing_if = "is_none_or_empty_string" ,
55+ rename = "ca_bundle_file"
56+ ) ]
57+ #[ arg( long, required = false ) ]
58+ pub proxy_ca_bundle_file : Option < String > ,
59+
60+ #[ arg( long, default_value_t = false , value_parser = ignore_system_proxy_parser, action = clap:: ArgAction :: Set ) ]
61+ pub ignore_system_proxy : bool ,
62+ }
63+
64+ // Helper to avoid serializing empty values
65+ fn is_none_or_empty_string ( v : & Option < String > ) -> bool {
66+ v. as_ref ( ) . map ( |s| s. is_empty ( ) ) . unwrap_or ( true )
67+ }
68+
69+ // Custom parser to allow empty values as false booleans
70+ fn ignore_system_proxy_parser ( s : & str ) -> Result < bool , Infallible > {
71+ match s. to_lowercase ( ) . as_str ( ) {
72+ "" | "false" => Ok ( false ) ,
73+ _ => Ok ( true ) ,
74+ }
75+ }
76+
3977/// Configuration to be written as result of the corresponding command.
4078#[ derive( Debug , PartialEq , Serialize ) ]
4179pub struct Config {
@@ -84,6 +122,7 @@ pub struct Agent {
84122#[ cfg( test) ]
85123mod tests {
86124 use super :: * ;
125+ use clap:: { Args , FromArgMatches } ;
87126 use rstest:: rstest;
88127
89128 #[ rstest]
@@ -109,4 +148,54 @@ mod tests {
109148
110149 assert_eq ! ( result, expected_map) ;
111150 }
151+
152+ #[ test]
153+ fn test_serialize_proxy_config_all_empty_options ( ) {
154+ let proxy_config = ProxyConfig {
155+ proxy_url : Some ( String :: new ( ) ) ,
156+ proxy_ca_bundle_dir : Some ( String :: new ( ) ) ,
157+ proxy_ca_bundle_file : Some ( String :: new ( ) ) ,
158+ ignore_system_proxy : false ,
159+ } ;
160+
161+ let serialized = serde_yaml:: to_string ( & proxy_config) . unwrap ( ) ;
162+ // Only ignore_system_proxy should be present
163+ assert_eq ! ( serialized. trim( ) , "ignore_system_proxy: false" ) ;
164+ }
165+
166+ #[ test]
167+ fn test_serialize_proxy_config_none_options ( ) {
168+ let proxy_config = ProxyConfig {
169+ proxy_url : None ,
170+ proxy_ca_bundle_dir : None ,
171+ proxy_ca_bundle_file : None ,
172+ ignore_system_proxy : true ,
173+ } ;
174+
175+ let serialized = serde_yaml:: to_string ( & proxy_config) . unwrap ( ) ;
176+ // Only ignore_system_proxy should be present
177+ assert_eq ! ( serialized. trim( ) , "ignore_system_proxy: true" ) ;
178+ }
179+
180+ #[ rstest]
181+ #[ case( "" , ProxyConfig :: default ( ) ) ]
182+ #[ case(
183+ "--proxy-url https://proxy.url --proxy-ca-bundle-dir=/bundle/dir --proxy-ca-bundle-file=/bundle/file --ignore-system-proxy true" ,
184+ ProxyConfig { proxy_url: Some ( "https://proxy.url" . into( ) ) , proxy_ca_bundle_dir: Some ( "/bundle/dir" . into( ) ) , proxy_ca_bundle_file: Some ( "/bundle/file" . into( ) ) , ignore_system_proxy: true } ,
185+ ) ]
186+ #[ case( "--proxy-url= --proxy-ca-bundle-dir= --proxy-ca-bundle-file= --ignore-system-proxy=" , ProxyConfig { proxy_url: Some ( "" . into( ) ) , proxy_ca_bundle_dir: Some ( "" . into( ) ) , proxy_ca_bundle_file: Some ( "" . into( ) ) , ignore_system_proxy: false } ) ]
187+ #[ case( " --ignore-system-proxy=" , ProxyConfig { ignore_system_proxy: false , ..Default :: default ( ) } ) ]
188+ #[ case( " --ignore-system-proxy=false" , ProxyConfig { ignore_system_proxy: false , ..Default :: default ( ) } ) ]
189+ #[ case( " --ignore-system-proxy=true" , ProxyConfig { ignore_system_proxy: true , ..Default :: default ( ) } ) ]
190+ #[ case( " --ignore-system-proxy=False" , ProxyConfig { ignore_system_proxy: false , ..Default :: default ( ) } ) ]
191+ #[ case( " --ignore-system-proxy=True" , ProxyConfig { ignore_system_proxy: true , ..Default :: default ( ) } ) ]
192+ fn test_proxy_args ( #[ case] args : & str , #[ case] expected : ProxyConfig ) {
193+ let cmd = clap:: Command :: new ( "test" ) . no_binary_name ( true ) ;
194+ let cmd = ProxyConfig :: augment_args ( cmd) ;
195+ let matches = cmd
196+ . try_get_matches_from ( args. split_ascii_whitespace ( ) )
197+ . expect ( "arguments should be valid" ) ;
198+ let value = ProxyConfig :: from_arg_matches ( & matches) . expect ( "should create the struct back" ) ;
199+ assert_eq ! ( value, expected)
200+ }
112201}
0 commit comments