20260914 完善OSS日志与daemon部署
This commit is contained in:
70
tests/logging_contract.rs
Normal file
70
tests/logging_contract.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
use std::process::Command;
|
||||
|
||||
#[test]
|
||||
fn default_format_is_human_readable_text() {
|
||||
let result = Command::new(env!("CARGO_BIN_EXE_panda-rpki"))
|
||||
.env_remove("PANDA_RPKI_LOG_FORMAT")
|
||||
.env_remove("PANDA_RPKI_LOG_LEVEL")
|
||||
.args(["validate"])
|
||||
.output()
|
||||
.unwrap();
|
||||
let diagnostic = String::from_utf8(result.stderr).unwrap();
|
||||
assert_eq!(result.status.code(), Some(2));
|
||||
assert!(diagnostic.contains("ERROR Command failed"));
|
||||
assert!(!diagnostic.contains("command_failed"));
|
||||
let call_line = include_str!("../src/main.rs")
|
||||
.lines()
|
||||
.position(|line| line.contains("panda_rpki::logging::emit("))
|
||||
.unwrap()
|
||||
+ 1;
|
||||
assert!(diagnostic.ends_with(&format!("[src/main.rs:{call_line}]\n")));
|
||||
assert!(result.stdout.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_progress_interval_is_rejected_without_outputs() {
|
||||
for value in ["-1", "wrong", "18446744073709551616"] {
|
||||
let result = Command::new(env!("CARGO_BIN_EXE_panda-rpki"))
|
||||
.args(["validate", "--log-progress-interval-secs", value])
|
||||
.output()
|
||||
.unwrap();
|
||||
assert_eq!(result.status.code(), Some(2));
|
||||
assert!(result.stdout.is_empty());
|
||||
assert!(String::from_utf8_lossy(&result.stderr).contains("log-progress-interval-secs"));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn progress_cli_overrides_invalid_environment() {
|
||||
let result = Command::new(env!("CARGO_BIN_EXE_panda-rpki"))
|
||||
.env("PANDA_RPKI_LOG_PROGRESS_INTERVAL_SECS", "invalid")
|
||||
.args([
|
||||
"validate",
|
||||
"--log-progress-interval-secs",
|
||||
"0",
|
||||
"--log-format",
|
||||
"json",
|
||||
])
|
||||
.output()
|
||||
.unwrap();
|
||||
let record: serde_json::Value = serde_json::from_slice(&result.stderr).unwrap();
|
||||
let call_line = include_str!("../src/main.rs")
|
||||
.lines()
|
||||
.position(|line| line.contains("panda_rpki::logging::emit("))
|
||||
.unwrap()
|
||||
+ 1;
|
||||
assert_eq!(record["source"]["file"], "src/main.rs");
|
||||
assert_eq!(record["source"]["line"], call_line);
|
||||
assert!(
|
||||
record["fields"]["error"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.contains("--tal")
|
||||
);
|
||||
assert!(
|
||||
!record["fields"]["error"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.contains("progress")
|
||||
);
|
||||
}
|
||||
@@ -86,6 +86,16 @@ def run(binary):
|
||||
assert gap >= 1.9, gap
|
||||
for seq in (1, 2):
|
||||
out = root / f"runs/run_{seq:06}"
|
||||
assert not (out / "stderr.log").exists()
|
||||
assert not (out / "stdout.log").exists()
|
||||
assert (out / "process-output.txt").read_bytes() == b""
|
||||
records = [json.loads(line) for line in (out / "validator.log").read_text().splitlines()]
|
||||
assert records[-1]["event"] == "validation_completed", records[-1]
|
||||
assert all(record["source"]["line"] > 0 and record["source"]["file"].endswith(".rs") for record in records)
|
||||
assert all(record["source"]["file"] not in ("src/logging.rs", "src/logging/progress.rs") for record in records)
|
||||
assert all(record["fields"]["run_seq"] == seq for record in records)
|
||||
assert len({record["fields"]["run_id"] for record in records}) == 1
|
||||
assert any(record["event"] == "artifact_write_completed" for record in records)
|
||||
assert len((out / "vrps.csv").read_text().splitlines()) - 1 == seq
|
||||
subprocess.run(["openssl", "asn1parse", "-inform", "DER", "-in",
|
||||
str(out / "result.ccr"), "-noout"], check=True)
|
||||
@@ -106,6 +116,15 @@ def run(binary):
|
||||
assert state_is(root, "exited")
|
||||
|
||||
# A real validator failure is recorded, retried, and returned as nonzero at max-runs.
|
||||
output_failure = subprocess.run(
|
||||
[binary, "validate", *child_args, "--out", str(base / "bad-output"), "--ccr-out", str(base)],
|
||||
capture_output=True, text=True, timeout=30,
|
||||
)
|
||||
assert output_failure.returncode == 2 and not output_failure.stdout
|
||||
failure_records = [json.loads(line) for line in output_failure.stderr.splitlines()]
|
||||
assert any(record["event"] == "artifact_write_failed" and record["fields"]["artifact_type"] == "ccr" for record in failure_records)
|
||||
assert any(record["event"] == "validation_stage_failed" for record in failure_records)
|
||||
assert not any(record["event"] == "validation_completed" for record in failure_records)
|
||||
failed = base / "failed"
|
||||
bad_inputs = ["--tal", str(base / "missing.tal"), "--ta", str(base / "missing.cer")]
|
||||
failure = launch(failed, ["--max-runs", "2", "--interval-secs", "0"], bad_inputs)
|
||||
@@ -115,10 +134,33 @@ def run(binary):
|
||||
|
||||
# Suspend the HTTPS server so the actual validator cannot complete a request.
|
||||
server.send_signal(signal.SIGSTOP)
|
||||
slow_inputs = list(child_args)
|
||||
slow_inputs[slow_inputs.index("--http-timeout-secs") + 1] = "30"
|
||||
slow_inputs += ["--log-progress-interval-secs", "1"]
|
||||
progress_root = base / "progress"
|
||||
progress = launch(progress_root, ["--max-runs", "1", "--run-timeout-secs", "20"], slow_inputs)
|
||||
progress_log = progress_root / "runs/run_000001/validator.log"
|
||||
|
||||
def has_progress():
|
||||
if not progress_log.exists():
|
||||
return False
|
||||
lines = progress_log.read_text().splitlines()
|
||||
return sum('"event":"validation_progress"' in line for line in lines) >= 2
|
||||
|
||||
wait_for(has_progress, "periodic progress during blocked network", timeout=15)
|
||||
server.send_signal(signal.SIGCONT)
|
||||
assert progress.wait(timeout=30) == 0
|
||||
progress_records = [json.loads(line) for line in progress_log.read_text().splitlines()]
|
||||
assert progress_records[-1]["event"] == "validation_completed"
|
||||
assert any(record["event"] == "validation_progress" and record["fields"]["repository_attempts_inflight"] > 0 for record in progress_records)
|
||||
server.send_signal(signal.SIGSTOP)
|
||||
hung = base / "timeout"
|
||||
timeout = launch(hung, ["--max-runs", "1", "--run-timeout-secs", "1"])
|
||||
disabled_inputs = list(slow_inputs)
|
||||
disabled_inputs[-1] = "0"
|
||||
timeout = launch(hung, ["--max-runs", "1", "--run-timeout-secs", "2"], disabled_inputs)
|
||||
assert timeout.wait(timeout=10) == 2
|
||||
assert read(hung / "runs/run_000001/run-summary.json")["error"] == "timeout"
|
||||
assert '"event":"validation_progress"' not in (hung / "runs/run_000001/validator.log").read_text()
|
||||
interrupted = base / "interrupted"
|
||||
active_proc = launch(interrupted, ["--shutdown-grace-secs", "0"])
|
||||
wait_for(lambda: state_is(interrupted, "running"), "active validator")
|
||||
|
||||
Reference in New Issue
Block a user