use super::*;
use serde_json::Value;
#[test]
fn result_is_error_true_fails() {
let v: Value = serde_json::from_str(
r#"{"type":"result","subtype":"error_during_execution","is_error":true}"#,
)
.unwrap();
assert!(result_envelope_failed(&v));
}
#[test]
fn result_success_is_error_false_ok() {
let v: Value = serde_json::from_str(
r#"{"type":"result","subtype":"success","is_error":false,"result":"ok"}"#,
)
.unwrap();
assert!(!result_envelope_failed(&v));
}
#[test]
fn nested_opencode_error_type_fails() {
let out = r#"{"type":"error","error":{"name":"UnknownError","data":{"message":"x"}}}"#;
assert_eq!(
status_from_result_jsonl(out).status,
TaskStatus::Failed
);
}
#[test]
fn record_quota_exhaustion_ignores_agent_prose_about_rate_limits() {
let temp = tempfile::tempdir().unwrap();
let _aid_home = crate::paths::AidHomeGuard::set(temp.path());
crate::rate_limit::clear_rate_limit(&crate::types::AgentKind::Cursor);
let report = format!(
"Conclusion: {}\n",
"The RPC provider throttles us; we saw a 429 and burned Alchemy credits"
);
assert!(!record_quota_exhaustion(
&report,
crate::types::AgentKind::Cursor,
None,
)
.recorded());
assert!(!crate::rate_limit::is_rate_limited(&crate::types::AgentKind::Cursor));
}
#[test]
fn record_quota_exhaustion_detects_provider_refusal_templates() {
let temp = tempfile::tempdir().unwrap();
let _aid_home = crate::paths::AidHomeGuard::set(temp.path());
crate::rate_limit::clear_rate_limit(&crate::types::AgentKind::Qwen);
let qwen_out = "Quota exhausted: Your token-plan 5-hour quota has been exhausted.";
assert!(record_quota_exhaustion(
qwen_out,
crate::types::AgentKind::Qwen,
None,
)
.should_fail());
assert!(crate::rate_limit::is_rate_limited(&crate::types::AgentKind::Qwen));
crate::rate_limit::clear_rate_limit(&crate::types::AgentKind::Qwen);
crate::rate_limit::clear_rate_limit(&crate::types::AgentKind::Codex);
let codex_out = "You have hit your usage limit. try again at Mar 21st, 2099 2:27 PM.";
assert!(record_quota_exhaustion(
codex_out,
crate::types::AgentKind::Codex,
None,
)
.should_fail());
assert!(crate::rate_limit::is_rate_limited(&crate::types::AgentKind::Codex));
}
#[test]
fn prose_rate_limit_tokens_are_not_quota_failures() {
assert!(!crate::rate_limit::is_rate_limit_error(
"rate_limit_kind now returns AgentKind::Custom for custom agents"
));
assert!(!crate::rate_limit::is_rate_limit_error(
"We must respect the rate limit on the Base sequencer feed"
));
assert!(!crate::rate_limit::is_rate_limit_error(
"The parser handles nested arrays correctly"
));
}
#[test]
fn record_quota_exhaustion_marks_but_does_not_fail_substantive_deliverable() {
let temp = tempfile::tempdir().unwrap();
let _aid_home = crate::paths::AidHomeGuard::set(temp.path());
crate::rate_limit::clear_rate_limit(&crate::types::AgentKind::Qwen);
let mut report = String::from("## Findings\n\n");
report.push_str(&"The audit reviewed rate limits and 429 handling. ".repeat(20));
report.push_str("\nQuota exhausted: Your token-plan 5-hour quota has been exhausted.");
assert!(!record_quota_exhaustion(
&report,
crate::types::AgentKind::Qwen,
None,
)
.should_fail());
assert!(crate::rate_limit::is_rate_limited(&crate::types::AgentKind::Qwen));
}
#[test]
fn record_quota_exhaustion_marks_refusal_even_behind_markdown_heading() {
let temp = tempfile::tempdir().unwrap();
let _aid_home = crate::paths::AidHomeGuard::set(temp.path());
crate::rate_limit::clear_rate_limit(&crate::types::AgentKind::Qwen);
let output = "# Error\nQuota exhausted: Your token-plan 5-hour quota has been exhausted.";
assert!(!record_quota_exhaustion(
output,
crate::types::AgentKind::Qwen,
None,
)
.should_fail());
assert!(crate::rate_limit::is_rate_limited(&crate::types::AgentKind::Qwen));
}
#[test]
fn unobserved_providers_are_not_guessed_from_generic_prose() {
let temp = tempfile::tempdir().unwrap();
let _aid_home = crate::paths::AidHomeGuard::set(temp.path());
for agent in [crate::types::AgentKind::Claude, crate::types::AgentKind::Grok] {
crate::rate_limit::clear_rate_limit(&agent);
assert!(!record_quota_exhaustion("429 Too Many Requests", agent, None).recorded());
assert!(!crate::rate_limit::is_rate_limited(&agent));
}
crate::rate_limit::clear_rate_limit(&crate::types::AgentKind::Cursor);
for line in ["429", "## Rate Limit", "Task 429", "Rate Limit"] {
assert!(!record_quota_exhaustion(line, crate::types::AgentKind::Cursor, None).recorded());
}
assert!(!crate::rate_limit::is_rate_limited(&crate::types::AgentKind::Cursor));
}
#[test]
fn quota_line_anchors_on_signature_needle_without_quota_word() {
let output = "402 payment required: reload your tokens";
let line = quota_line(output, crate::types::AgentKind::Droid).expect("droid line");
assert!(line.contains("reload your tokens"));
assert!(line.starts_with("402"));
}
#[test]
fn record_quota_exhaustion_ignores_signature_source_citations() {
let temp = tempfile::tempdir().unwrap();
let _aid_home = crate::paths::AidHomeGuard::set(temp.path());
crate::rate_limit::clear_rate_limit(&crate::types::AgentKind::OpenCode);
let output = "QuotaSignature { agent: AgentKind::OpenCode, needle: \"insufficient balance\", fallback_minutes: 1440 },";
assert!(!record_quota_exhaustion(
output,
crate::types::AgentKind::OpenCode,
None,
)
.recorded());
assert!(!crate::rate_limit::is_rate_limited(&crate::types::AgentKind::OpenCode));
}
#[test]
fn a_delivered_run_that_hit_a_refusal_keeps_its_marker() {
let temp = tempfile::tempdir().unwrap();
let _aid_home = crate::paths::AidHomeGuard::set(temp.path());
crate::rate_limit::clear_rate_limit(&crate::types::AgentKind::Qwen);
let mut report = String::from("## Findings\n\n");
report.push_str(&"Reviewed the adapter and its tests. ".repeat(20));
report.push_str("\nQuota exhausted: Your token-plan 5-hour quota has been exhausted.");
let outcome = record_quota_exhaustion(&report, crate::types::AgentKind::Qwen, None);
assert!(outcome.recorded(), "the outage must be recorded");
assert!(!outcome.should_fail(), "a run that delivered is not a failed task");
assert!(crate::rate_limit::is_rate_limited(&crate::types::AgentKind::Qwen));
}