From 8095aa5aaa91f89d5af29a2b16b01f95f425ff55 Mon Sep 17 00:00:00 2001 From: "rearden-grok[bot]" <317016512+rearden-grok[bot]@users.noreply.github.com> Date: Thu, 15 Oct 2026 21:28:21 -0700 Subject: [PATCH] test: restore conf units pasted into operator_conf_and_argv #1022 and #1023 concatenated private apply_kv cases and sibling ready_config checks into one function. Those are their own tests again. The work-queue asserts stay on argv. The mempool and sigop deletions stay because the life journeys already covered them. --- crates/rbitcoin-node/src/cli.rs | 129 ++++++++------------------ crates/rbitcoin-node/src/config.rs | 142 +++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+), 91 deletions(-) diff --git a/crates/rbitcoin-node/src/cli.rs b/crates/rbitcoin-node/src/cli.rs index 06d613cf8..e2821552f 100644 --- a/crates/rbitcoin-node/src/cli.rs +++ b/crates/rbitcoin-node/src/cli.rs @@ -846,15 +846,6 @@ mod tests { .unwrap_err() .to_string(); assert!(err.contains("sp_tweaks_dust"), "{err}"); - let bad_line = dir.join("bad.conf"); - std::fs::write(&bad_line, "secret-token-xyz\n").unwrap(); - let err = NodeConfig::default() - .merge_conf_file(&bad_line) - .unwrap_err() - .to_string(); - assert!(err.contains("bad.conf:1"), "{err}"); - assert!(err.contains("expected key=value"), "{err}"); - assert!(!err.contains("secret-token-xyz"), "{err}"); match operator_config_from_args(["rbitcoin-node", "--conf", bad_dust.to_str().unwrap()]) { Err(code) => assert_exit(code, ExitCode::from(2)), Ok(other) => panic!("bad sp_tweaks_dust conf assembled: {other:?}"), @@ -974,9 +965,6 @@ mod tests { assert_eq!(cfg.check_blocks, Some(stored)); assert_eq!(cfg.check_blocks_window(), window, "{arg}"); } - let mut bad_blocks = NodeConfig::default(); - let bad = bad_blocks.apply_kv("check_blocks", "nope").unwrap_err(); - assert!(bad.to_string().contains("check-blocks"), "{bad}"); for off in ["--no-listen", "--listen=0"] { let cfg = ready_config(["rbitcoin-node", off]); assert_eq!(cfg.listen.p2p, P2pListen::Off, "{off}"); @@ -1052,33 +1040,6 @@ mod tests { .unwrap_or_else(|e| panic!("{argv:?} must validate: {e}")); } - assert_eq!( - ready_config(["rbitcoin-node"]).electrum_max_subs, - rbitcoin_electrum::DEFAULT_MAX_SCRIPTHASH_SUBS - ); - assert_eq!( - ready_config(["rbitcoin-node", "--electrum-max-subs", "25000"]).electrum_max_subs, - 25_000 - ); - assert_eq!( - ready_config(["rbitcoin-node", "--electrum-max-subs=5"]).electrum_max_subs, - 5 - ); - let mut subs = NodeConfig::default(); - let zero = subs.apply_kv("electrum_max_subs", "0").unwrap_err(); - assert!(format!("{zero}").contains(">= 1"), "{zero}"); - let bad = subs.apply_kv("electrum_max_subs", "nope").unwrap_err(); - assert!(format!("{bad}").contains("electrum_max_subs"), "{bad}"); - assert_eq!( - subs.electrum_max_subs, - rbitcoin_electrum::DEFAULT_MAX_SCRIPTHASH_SUBS, - "a refused value leaves the default" - ); - assert!( - ready_config(["rbitcoin-node", "--esplora-block-template=1"]).esplora_block_template - ); - assert!(!ready_config(["rbitcoin-node", "--esplora-onion=0"]).esplora_onion); - // Zero is the finite default queue, not an unbounded one. assert_eq!( ready_config(["rbitcoin-node"]).rpc.work_queue, @@ -1096,69 +1057,55 @@ mod tests { .work_queue, Some(4) ); + } - let mut dir_cfg = NodeConfig::default(); + #[test] + fn electrum_max_subs_cli_conf_and_bounds() { assert_eq!( - dir_cfg.apply_kv("datadir", "/tmp/rb-apply-kv").unwrap(), - ConfApply::Applied + ready_config(["rbitcoin-node"]).electrum_max_subs, + rbitcoin_electrum::DEFAULT_MAX_SCRIPTHASH_SUBS ); assert_eq!( - dir_cfg.datadir.path(), - std::path::Path::new("/tmp/rb-apply-kv") + ready_config(["rbitcoin-node", "--electrum-max-subs", "25000"]).electrum_max_subs, + 25_000 ); - match dir_cfg.apply_kv("not-a-real-key", "1").unwrap() { - ConfApply::Unknown(k) => assert_eq!(k, "not-a-real-key"), - other => panic!("{other:?}"), - } - - let mut blocks = NodeConfig::default(); - for key in ["blocks_dir", "blocks-dir", "blocksdir"] { - assert_eq!( - blocks.apply_kv(key, "/tmp/x").unwrap(), - ConfApply::Unknown(key.into()), - "{key} is not an operator key" - ); - } - - let mut listen = NodeConfig::default(); - listen.apply_kv("listen", "127.0.0.1:18444").unwrap(); - let dup = listen - .apply_kv("listen", "127.0.0.1:18444") - .unwrap_err() - .to_string(); - assert!(dup.contains("Duplicate binding configuration"), "{dup}"); - - let mut sock_cfg = - NodeConfig::default().with_datadir(std::path::Path::new("/var/lib/rbitcoin")); assert_eq!( - sock_cfg.rpc_socket_path(), - std::path::Path::new("/var/lib/rbitcoin/rpc.sock") + ready_config(["rbitcoin-node", "--electrum-max-subs=5"]).electrum_max_subs, + 5 ); + let mut c = NodeConfig::default(); + let zero = c.apply_kv("electrum_max_subs", "0").unwrap_err(); + assert!(format!("{zero}").contains(">= 1"), "{zero}"); + let bad = c.apply_kv("electrum_max_subs", "nope").unwrap_err(); + assert!(format!("{bad}").contains("electrum_max_subs"), "{bad}"); assert_eq!( - sock_cfg - .apply_kv("rpc_socket", "/run/rbitcoin/rpc.sock") - .unwrap(), - ConfApply::Applied + c.electrum_max_subs, + rbitcoin_electrum::DEFAULT_MAX_SCRIPTHASH_SUBS, + "a refused value leaves the default" ); - assert!(sock_cfg.rpc.socket, "rpc_socket implies rpc"); + } + + #[test] + fn max_sh_creates_and_esplora_block_template_cli_hyphens() { + let omitted = ready_config(["rbitcoin-node"]); assert_eq!( - sock_cfg.rpc_socket_path(), - std::path::Path::new("/run/rbitcoin/rpc.sock") + omitted.max_sh_creates, + rbitcoin_query::DEFAULT_MAX_SH_CREATES ); - let empty = NodeConfig::default() - .apply_kv("rpc_socket", "") - .unwrap_err() - .to_string(); - assert!(empty.contains("rpc_socket requires a path"), "{empty}"); - - let mut tor = NodeConfig::default(); - let cr = tor - .apply_kv("tor_control_password", "a\nb") - .unwrap_err() - .to_string(); - assert!(cr.contains("CR"), "{cr}"); - tor.apply_kv("tor_control_password", "pw").unwrap(); - assert_eq!(tor.tor.password.as_deref(), Some("pw")); + assert!(!omitted.esplora_block_template); + let n = ready_config(["rbitcoin-node", "--max-sh-creates", "42"]); + assert_eq!(n.max_sh_creates, 42); + let eq = ready_config(["rbitcoin-node", "--max-sh-creates=9"]); + assert_eq!(eq.max_sh_creates, 9); + let gbt = ready_config(["rbitcoin-node", "--esplora-block-template"]); + assert!(gbt.esplora_block_template); + let gbt_eq = ready_config(["rbitcoin-node", "--esplora-block-template=1"]); + assert!(gbt_eq.esplora_block_template); + let off = ready_config(["rbitcoin-node", "--esplora-block-template=0"]); + assert!(!off.esplora_block_template); + assert!(NodeConfig::default().esplora_onion); + let onion_off = ready_config(["rbitcoin-node", "--esplora-onion=0"]); + assert!(!onion_off.esplora_onion); } include!("overlay_config_journey.rs"); diff --git a/crates/rbitcoin-node/src/config.rs b/crates/rbitcoin-node/src/config.rs index 2321e9460..0c99da0c4 100644 --- a/crates/rbitcoin-node/src/config.rs +++ b/crates/rbitcoin-node/src/config.rs @@ -1645,6 +1645,148 @@ mod tests { std::env::temp_dir().join(format!("rbitcoin-node-cfg-{n}")) } + #[test] + fn conf_error_names_the_file_and_line() { + let dir = std::env::temp_dir().join(format!("rbitcoin-conf-line-{}", std::process::id())); + let _ = std::fs::remove_dir_all(&dir); + std::fs::create_dir_all(&dir).unwrap(); + let path = dir.join("bad.conf"); + std::fs::write(&path, "secret-token-xyz\n").unwrap(); + let err = NodeConfig::default() + .merge_conf_file(&path) + .unwrap_err() + .to_string(); + assert!(err.contains("bad.conf:1"), "{err}"); + assert!(err.contains("expected key=value"), "{err}"); + assert!(!err.contains("secret-token-xyz"), "{err}"); + let _ = std::fs::remove_dir_all(&dir); + } + + #[test] + fn check_blocks_apply_kv_zero_is_all() { + let mut c = NodeConfig::default(); + assert_eq!(c.check_blocks, None); + assert_eq!(c.check_blocks_window(), rbitcoin_store::VERIFY_TIP_BLOCKS); + assert_eq!(c.apply_kv("check_blocks", "6").unwrap(), ConfApply::Applied); + assert_eq!(c.check_blocks, Some(6)); + assert_eq!(c.check_blocks_window(), 6); + assert_eq!(c.apply_kv("check-blocks", "0").unwrap(), ConfApply::Applied); + assert_eq!(c.check_blocks, Some(0)); + assert_eq!(c.check_blocks_window(), 0); + assert_eq!( + c.apply_kv("check_blocks", "-1").unwrap(), + ConfApply::Applied + ); + assert_eq!(c.check_blocks, Some(-1)); + assert_eq!(c.check_blocks_window(), 0); + let bad = c.apply_kv("check_blocks", "nope").unwrap_err(); + assert!(bad.to_string().contains("check-blocks"), "{bad}"); + assert_eq!( + c.apply_kv("checkblocks", "6").unwrap(), + ConfApply::Unknown("checkblocks".into()) + ); + } + + #[test] + fn prefillcompact_cli_conf_default_on() { + let mut c = NodeConfig::default(); + assert!(c.prefill_compact); + match c.apply_kv("prefillcompact", "0").unwrap() { + ConfApply::Unknown(k) => assert_eq!(k, "prefillcompact"), + other => panic!("{other:?}"), + } + assert!(c.prefill_compact); + assert_eq!( + c.apply_kv("prefill_compact", "0").unwrap(), + ConfApply::Applied + ); + assert!(!c.prefill_compact); + assert_eq!( + c.apply_kv("prefill_compact", "1").unwrap(), + ConfApply::Applied + ); + assert!(c.prefill_compact); + } + + #[test] + fn tor_control_password_rejects_a_line_break() { + let mut c = NodeConfig::default(); + let err = c + .apply_kv("tor_control_password", "a\nb") + .unwrap_err() + .to_string(); + assert!(err.contains("CR"), "{err}"); + c.apply_kv("tor_control_password", "pw").unwrap(); + assert_eq!(c.tor.password.as_deref(), Some("pw")); + } + + #[test] + fn apply_kv_is_the_conf_setter_and_unknown_is_not_error() { + let mut c = NodeConfig::default(); + assert_eq!( + c.apply_kv("network", "regtest").unwrap(), + ConfApply::Applied + ); + assert_eq!(c.network, Network::Regtest); + assert_eq!( + c.apply_kv("datadir", "/tmp/rb-apply-kv").unwrap(), + ConfApply::Applied + ); + assert_eq!(c.datadir.path(), Path::new("/tmp/rb-apply-kv")); + match c.apply_kv("not-a-real-key", "1").unwrap() { + ConfApply::Unknown(k) => assert_eq!(k, "not-a-real-key"), + other => panic!("{other:?}"), + } + } + + #[test] + fn rpc_socket_moves_the_socket_out_of_the_datadir() { + let mut c = NodeConfig::default().with_datadir(Path::new("/var/lib/rbitcoin")); + assert_eq!(c.rpc_socket_path(), Path::new("/var/lib/rbitcoin/rpc.sock")); + assert_eq!( + c.apply_kv("rpc_socket", "/run/rbitcoin/rpc.sock").unwrap(), + ConfApply::Applied + ); + assert!(c.rpc.socket, "rpc_socket implies rpc"); + assert_eq!(c.rpc_socket_path(), Path::new("/run/rbitcoin/rpc.sock")); + let err = NodeConfig::default() + .apply_kv("rpc_socket", "") + .unwrap_err() + .to_string(); + assert!(err.contains("rpc_socket requires a path"), "{err}"); + } + + #[test] + fn blocks_dir_is_not_an_operator_key() { + let mut c = NodeConfig::default(); + assert_eq!( + c.apply_kv("blocks_dir", "/tmp/x").unwrap(), + ConfApply::Unknown("blocks_dir".into()) + ); + assert_eq!( + c.apply_kv("blocks-dir", "/tmp/x").unwrap(), + ConfApply::Unknown("blocks-dir".into()) + ); + assert_eq!( + c.apply_kv("blocksdir", "/tmp/x").unwrap(), + ConfApply::Unknown("blocksdir".into()) + ); + } + + #[test] + fn duplicate_listen_is_init_error() { + let mut c = NodeConfig::default(); + assert_eq!( + c.apply_kv("listen", "127.0.0.1:18444").unwrap(), + ConfApply::Applied + ); + let err = c.apply_kv("listen", "127.0.0.1:18444").unwrap_err(); + assert!( + err.to_string().contains("Duplicate binding configuration"), + "{err}" + ); + } + #[test] fn sv2_tp_apply_kv_and_listen_requires_authority() { let mut c = NodeConfig::default().with_datadir(tmp());