mirror of
https://github.com/TheFunny/TelegramTwitterMediaBot.git
synced 2026-09-26 23:52:05 +00:00
test(config): pin the webhook truth table, TTL fallback and blank secrets
Config::load had exactly one test (BOT_ADMIN parsing) while carrying the branches an operator is most likely to mistype: the WEBHOOK truth table (case-insensitive true|yes|1 — 'on' must not enable it), an unparseable EDIT_MESSAGE_TTL_SECONDS (warn + default, not a silent 0 that expires prompts instantly), and empty WEBHOOK_CERT/WEBHOOK_SECRET_TOKEN (compose injects ${VAR:-} as an empty string, which must read as unset, not as a one-character secret). Three table-style tests reuse the existing env save/restore pattern; none of them asserts a field another test reads, so they are safe under parallel execution.
This commit is contained in:
@@ -130,4 +130,95 @@ mod tests {
|
|||||||
}
|
}
|
||||||
assert_eq!(ids, vec![7, 42]);
|
assert_eq!(ids, vec![7, 42]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The webhook truth table: `Config::load` enables webhook mode only for
|
||||||
|
/// a case-insensitive `true|yes|1`, and everything else — including the
|
||||||
|
/// classic misspelling "on", which an operator would expect to work — is
|
||||||
|
/// polling. Without this pin a typo silently ran a different transport
|
||||||
|
/// (with P0's fail-fast secret check, or with no listener at all).
|
||||||
|
#[test]
|
||||||
|
fn webhook_flag_is_a_case_insensitive_truth_table() {
|
||||||
|
// SAFETY: no other test *mutates* WEBHOOK, the value is restored
|
||||||
|
// before this test returns, and concurrent Config::load callers in
|
||||||
|
// other tests assert fields other than webhook_enabled.
|
||||||
|
let previous = env::var("WEBHOOK").ok();
|
||||||
|
for (value, expected) in [
|
||||||
|
("true", true),
|
||||||
|
("TRUE", true),
|
||||||
|
("Yes", true),
|
||||||
|
("1", true),
|
||||||
|
("false", false),
|
||||||
|
("on", false),
|
||||||
|
("", false),
|
||||||
|
] {
|
||||||
|
unsafe { env::set_var("WEBHOOK", value) };
|
||||||
|
assert_eq!(
|
||||||
|
Config::load().webhook_enabled,
|
||||||
|
expected,
|
||||||
|
"WEBHOOK={value:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
match previous {
|
||||||
|
Some(value) => unsafe { env::set_var("WEBHOOK", value) },
|
||||||
|
None => unsafe { env::remove_var("WEBHOOK") },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A malformed TTL warns and falls back to the default instead of being
|
||||||
|
/// parsed as 0 — the difference between a 24h edit-prompt expiry and a
|
||||||
|
/// prompt that expires instantly, which an operator would only notice
|
||||||
|
/// when the buttons stop working.
|
||||||
|
#[test]
|
||||||
|
fn invalid_ttl_falls_back_to_the_default() {
|
||||||
|
// SAFETY: no other test *mutates* EDIT_MESSAGE_TTL_SECONDS; restored
|
||||||
|
// below, and no other test asserts the TTL field.
|
||||||
|
let previous = env::var("EDIT_MESSAGE_TTL_SECONDS").ok();
|
||||||
|
unsafe { env::set_var("EDIT_MESSAGE_TTL_SECONDS", "not-a-number") };
|
||||||
|
let invalid = Config::load().edit_message_ttl;
|
||||||
|
unsafe { env::set_var("EDIT_MESSAGE_TTL_SECONDS", "120") };
|
||||||
|
let valid = Config::load().edit_message_ttl;
|
||||||
|
match previous {
|
||||||
|
Some(value) => unsafe { env::set_var("EDIT_MESSAGE_TTL_SECONDS", value) },
|
||||||
|
None => unsafe { env::remove_var("EDIT_MESSAGE_TTL_SECONDS") },
|
||||||
|
}
|
||||||
|
assert_eq!(
|
||||||
|
invalid,
|
||||||
|
Duration::from_secs(24 * 3600),
|
||||||
|
"an unparseable value falls back to the default"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
valid,
|
||||||
|
Duration::from_secs(120),
|
||||||
|
"a valid value is taken as-is"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A blank WEBHOOK_CERT / WEBHOOK_SECRET_TOKEN counts as unset — compose
|
||||||
|
/// injects `${VAR:-}` as an empty string for a commented-out template
|
||||||
|
/// line — while a present value is kept (the `-e VAR=` disable idiom).
|
||||||
|
#[test]
|
||||||
|
fn blank_webhook_cert_and_secret_count_as_unset() {
|
||||||
|
// SAFETY: no other test *mutates* these two, both are restored
|
||||||
|
// below, and no other test asserts them.
|
||||||
|
let prev_cert = env::var("WEBHOOK_CERT").ok();
|
||||||
|
let prev_secret = env::var("WEBHOOK_SECRET_TOKEN").ok();
|
||||||
|
unsafe { env::set_var("WEBHOOK_CERT", "") };
|
||||||
|
unsafe { env::set_var("WEBHOOK_SECRET_TOKEN", "") };
|
||||||
|
let blank = Config::load();
|
||||||
|
unsafe { env::set_var("WEBHOOK_CERT", "/x/cert.pem") };
|
||||||
|
unsafe { env::set_var("WEBHOOK_SECRET_TOKEN", "s3cret") };
|
||||||
|
let present = Config::load();
|
||||||
|
match prev_cert {
|
||||||
|
Some(value) => unsafe { env::set_var("WEBHOOK_CERT", value) },
|
||||||
|
None => unsafe { env::remove_var("WEBHOOK_CERT") },
|
||||||
|
}
|
||||||
|
match prev_secret {
|
||||||
|
Some(value) => unsafe { env::set_var("WEBHOOK_SECRET_TOKEN", value) },
|
||||||
|
None => unsafe { env::remove_var("WEBHOOK_SECRET_TOKEN") },
|
||||||
|
}
|
||||||
|
assert_eq!(blank.webhook_cert, None, "blank must read as unset");
|
||||||
|
assert_eq!(blank.webhook_secret_token, None, "blank must read as unset");
|
||||||
|
assert_eq!(present.webhook_cert.as_deref(), Some("/x/cert.pem"));
|
||||||
|
assert_eq!(present.webhook_secret_token.as_deref(), Some("s3cret"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user