configmodel: impl Config for BTreeMap<&str, &str>

Summary:
This is often more convenient in tests inserting &'static str. I left the String impl since I can imagine cases where borrowed data is not convenient.

I tried to make it generic, but couldn't come up with something that maintained ergonomics for users.

Reviewed By: sggutier

Differential Revision: D35985480

fbshipit-source-id: e3802c35ebd3f945692c004eb34b454e576c9195
This commit is contained in:
Muir Manders 2022-05-10 07:38:55 -07:00 committed by Facebook GitHub Bot
parent 516039d171
commit 2407963405
5 changed files with 49 additions and 76 deletions

View File

@ -77,23 +77,30 @@ impl Config for &dyn Config {
} }
} }
impl Config for BTreeMap<String, String> { impl Config for BTreeMap<&str, &str> {
fn keys(&self, section: &str) -> Vec<Text> { fn keys(&self, section: &str) -> Vec<Text> {
let prefix = format!("{}.", section); let prefix = format!("{}.", section);
BTreeMap::keys(&self) BTreeMap::keys(self)
.filter_map(|k| { .filter_map(|k| k.strip_prefix(&prefix).map(|k| k.to_string().into()))
if k.starts_with(&prefix) {
Some(k[prefix.len()..].to_string().into())
} else {
None
}
})
.collect() .collect()
} }
fn get(&self, section: &str, name: &str) -> Option<Text> { fn get(&self, section: &str, name: &str) -> Option<Text> {
let name = format!("{}.{}", section, name); let key: &str = &format!("{}.{}", section, name);
BTreeMap::get(self, &name).map(|v| v.to_string().into()) BTreeMap::get(self, &key).map(|v| v.to_string().into())
}
}
impl Config for BTreeMap<String, String> {
fn keys(&self, section: &str) -> Vec<Text> {
let prefix = format!("{}.", section);
BTreeMap::keys(self)
.filter_map(|k| k.strip_prefix(&prefix).map(|k| k.to_string().into()))
.collect()
}
fn get(&self, section: &str, name: &str) -> Option<Text> {
BTreeMap::get(self, &format!("{}.{}", section, name)).map(|v| v.clone().into())
} }
} }
@ -103,9 +110,7 @@ mod tests {
#[test] #[test]
fn test_btreemap_config() { fn test_btreemap_config() {
let map: BTreeMap<String, String> = vec![("foo.bar".to_string(), "baz".to_string())] let map: BTreeMap<&str, &str> = vec![("foo.bar", "baz")].into_iter().collect();
.into_iter()
.collect();
assert_eq!(format!("{:?}", Config::keys(&map, "foo")), "[\"bar\"]"); assert_eq!(format!("{:?}", Config::keys(&map, "foo")), "[\"bar\"]");
assert_eq!( assert_eq!(
format!("{:?}", Config::get(&map, "foo", "bar")), format!("{:?}", Config::get(&map, "foo", "bar")),

View File

@ -527,11 +527,8 @@ mod tests {
// Both corp and external fail. // Both corp and external fail.
{ {
let mut cfg = BTreeMap::new(); let mut cfg = BTreeMap::new();
cfg.insert("edenapi.url".to_string(), non_working_url.to_string()); cfg.insert("edenapi.url", non_working_url);
cfg.insert( cfg.insert("doctor.external-host-check-url", non_working_url);
"doctor.external-host-check-url".to_string(),
non_working_url.to_string(),
);
let mut doc = Doctor::new(); let mut doc = Doctor::new();
doc.tcp_connect_timeout = Duration::from_millis(1); doc.tcp_connect_timeout = Duration::from_millis(1);
@ -549,11 +546,8 @@ mod tests {
// External works. // External works.
{ {
let mut cfg = BTreeMap::new(); let mut cfg = BTreeMap::new();
cfg.insert("edenapi.url".to_string(), non_working_url.to_string()); cfg.insert("edenapi.url", non_working_url);
cfg.insert( cfg.insert("doctor.external-host-check-url", &working_url);
"doctor.external-host-check-url".to_string(),
working_url.to_string(),
);
let doc = Doctor::new(); let doc = Doctor::new();
assert!(matches!( assert!(matches!(
@ -564,12 +558,9 @@ mod tests {
// Corp works. // Corp works.
{ {
let mut cfg = BTreeMap::new(); let mut cfg: BTreeMap<&str, &str> = BTreeMap::new();
cfg.insert("edenapi.url".to_string(), working_url.to_string()); cfg.insert("edenapi.url", &working_url);
cfg.insert( cfg.insert("doctor.external-host-check-url", &working_url);
"doctor.external-host-check-url".to_string(),
working_url.to_string(),
);
let doc = Doctor::new(); let doc = Doctor::new();
assert!(matches!(doc.check_corp_connectivity(&cfg), Ok(()))); assert!(matches!(doc.check_corp_connectivity(&cfg), Ok(())));
@ -586,23 +577,11 @@ mod tests {
std::fs::write(&fake_cert_path, "foo").unwrap(); std::fs::write(&fake_cert_path, "foo").unwrap();
let mut cfg = BTreeMap::new(); let mut cfg = BTreeMap::new();
cfg.insert( cfg.insert("edenapi.url", "https://example.com/edenapi/");
"edenapi.url".to_string(), cfg.insert("remotefilelog.reponame", "some_repo");
"https://example.com/edenapi/".to_string(), cfg.insert("auth.test.prefix", "*");
); cfg.insert("auth.test.cert", fake_cert_path.to_str().unwrap());
cfg.insert( cfg.insert("auth.test.key", fake_cert_path.to_str().unwrap());
"remotefilelog.reponame".to_string(),
"some_repo".to_string(),
);
cfg.insert("auth.test.prefix".to_string(), "*".to_string());
cfg.insert(
"auth.test.cert".to_string(),
fake_cert_path.to_string_lossy().to_string(),
);
cfg.insert(
"auth.test.key".to_string(),
fake_cert_path.to_string_lossy().to_string(),
);
// Happy path - server returns 200 for /capabilities. // Happy path - server returns 200 for /capabilities.
{ {
@ -633,14 +612,8 @@ mod tests {
{ {
let mut cfg = cfg.clone(); let mut cfg = cfg.clone();
cfg.insert( cfg.insert("auth_proxy.unix_socket_path", "/dev/null");
"auth_proxy.unix_socket_path".to_string(), cfg.insert("auth_proxy.unix_socket_domains", "example.com");
"/dev/null".to_string(),
);
cfg.insert(
"auth_proxy.unix_socket_domains".to_string(),
"example.com".to_string(),
);
// Simulate x2pagentd specific problem. // Simulate x2pagentd specific problem.
doc.stub_healthcheck_response = Some(Box::new(|_url, x2p| { doc.stub_healthcheck_response = Some(Box::new(|_url, x2p| {
@ -665,12 +638,9 @@ mod tests {
{ {
let mut cfg = cfg.clone(); let mut cfg = cfg.clone();
cfg.insert( cfg.insert("edenapi.url", "http://example.com/edenapi/");
"edenapi.url".to_string(),
"http://example.com/edenapi/".to_string(),
);
cfg.insert("auth.test.prefix".to_string(), "doesnt_match".to_string()); cfg.insert("auth.test.prefix", "doesnt_match");
doc.stub_healthcheck_response = doc.stub_healthcheck_response =
Some(Box::new(|_url, _x2p| Ok(response!(http::StatusCode::OK)))); Some(Box::new(|_url, _x2p| Ok(response!(http::StatusCode::OK))));
@ -681,7 +651,7 @@ mod tests {
{ {
let mut cfg = cfg.clone(); let mut cfg = cfg.clone();
cfg.insert("auth.test.prefix".to_string(), "doesnt_match".to_string()); cfg.insert("auth.test.prefix", "doesnt_match");
doc.stub_healthcheck_response = doc.stub_healthcheck_response =
Some(Box::new(|_url, _x2p| Ok(response!(http::StatusCode::OK)))); Some(Box::new(|_url, _x2p| Ok(response!(http::StatusCode::OK))));

View File

@ -203,14 +203,14 @@ mod tests {
#[test] #[test]
fn test_convert_cert_config() { fn test_convert_cert_config() {
let mut hg_config = BTreeMap::<String, String>::new(); let mut hg_config = BTreeMap::<&str, &str>::new();
assert_eq!(cfg!(windows), http_config(&hg_config, None).convert_cert); assert_eq!(cfg!(windows), http_config(&hg_config, None).convert_cert);
hg_config.insert("http.convert-cert".into(), "True".into()); hg_config.insert("http.convert-cert", "True");
assert!(http_config(&hg_config, None).convert_cert); assert!(http_config(&hg_config, None).convert_cert);
hg_config.insert("http.convert-cert".into(), "false".into()); hg_config.insert("http.convert-cert", "false");
assert!(!http_config(&hg_config, None).convert_cert); assert!(!http_config(&hg_config, None).convert_cert);
} }
} }

View File

@ -224,8 +224,8 @@ mod tests {
#[test] #[test]
fn test_close() -> Result<()> { fn test_close() -> Result<()> {
let mut cfg = BTreeMap::new(); let mut cfg = BTreeMap::new();
cfg.insert("runlog.boring-commands".to_string(), "boring".to_string()); cfg.insert("runlog.boring-commands", "boring");
cfg.insert("runlog.enable".to_string(), "1".to_string()); cfg.insert("runlog.enable", "1");
let cleaned_up_files = |cfg, name: &str, exit: i32| -> Result<bool> { let cleaned_up_files = |cfg, name: &str, exit: i32| -> Result<bool> {
let td = tempdir()?; let td = tempdir()?;
@ -250,12 +250,12 @@ mod tests {
// Infer boringness from blackbox disablement. // Infer boringness from blackbox disablement.
let mut no_bb_cfg = cfg.clone(); let mut no_bb_cfg = cfg.clone();
no_bb_cfg.insert("extensions.blackbox".to_string(), "!".to_string()); no_bb_cfg.insert("extensions.blackbox", "!");
assert!(cleaned_up_files(&no_bb_cfg, "blackbox_disabled", 0)?); assert!(cleaned_up_files(&no_bb_cfg, "blackbox_disabled", 0)?);
// Infer boringness from empty blackbox.trace. // Infer boringness from empty blackbox.trace.
let mut no_bb_trace = cfg.clone(); let mut no_bb_trace = cfg.clone();
no_bb_trace.insert("blackbox.track".to_string(), "".to_string()); no_bb_trace.insert("blackbox.track", "");
assert!(cleaned_up_files(&no_bb_trace, "blackbox_disabled", 0)?); assert!(cleaned_up_files(&no_bb_trace, "blackbox_disabled", 0)?);
Ok(()) Ok(())
@ -265,7 +265,7 @@ mod tests {
fn test_empty_command() -> Result<()> { fn test_empty_command() -> Result<()> {
let td = tempdir()?; let td = tempdir()?;
let mut cfg = BTreeMap::new(); let mut cfg = BTreeMap::new();
cfg.insert("runlog.enable".to_string(), "1".to_string()); cfg.insert("runlog.enable", "1");
// Don't crash. // Don't crash.
Logger::new(&cfg, td.path(), vec![])?; Logger::new(&cfg, td.path(), vec![])?;

View File

@ -184,13 +184,11 @@ mod tests {
// layer not configured, shouldn't show up. // layer not configured, shouldn't show up.
tracing::info!(target: "banana", foo = "bar"); tracing::info!(target: "banana", foo = "bar");
let config = BTreeMap::<String, String>::from([ let filepath = out_path.to_string_lossy();
( let config = BTreeMap::<&str, &str>::from([
"sampling.filepath".to_string(), ("sampling.filepath", filepath.as_ref()),
out_path.to_string_lossy().to_string(), ("sampling.key.banana", "pear"),
), ("sampling.key.orange", "melon"),
("sampling.key.banana".to_string(), "pear".to_string()),
("sampling.key.orange".to_string(), "melon".to_string()),
]); ]);
sc.set(SamplingConfig::new(&config).unwrap()).unwrap(); sc.set(SamplingConfig::new(&config).unwrap()).unwrap();