const FATAL_ERROR_PATTERNS: &[&str] = &[
"dial tcp:",
"Client.Timeout exceeded",
"connection refused",
"no such host",
"request canceled while waiting for connection",
"request canceled (Client.Timeout",
"tls: handshake",
"certificate",
"network is unreachable",
"connection reset by peer",
"broken pipe",
"EOF",
"http response status code: 401",
"http response status code: 403",
];
const NON_FATAL_OVERRIDES: &[&str] = &[
"http response status code: 404",
"ResourceNotFoundException",
"was not found",
];
pub fn check_fatal_error(error_msg: &str) -> Option<&'static str> {
for pattern in NON_FATAL_OVERRIDES {
if error_msg.contains(pattern) {
return None;
}
}
FATAL_ERROR_PATTERNS
.iter()
.find(|&&pattern| error_msg.contains(pattern))
.copied()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_network_timeout_is_fatal() {
let msg = r#"Query execution failed: query returns error: Post "https://cloudcontrolapi.us-east-1.amazonaws.com/?Action=GetResource&Version=2021-09-30": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)"#;
assert!(check_fatal_error(msg).is_some());
}
#[test]
fn test_dns_failure_is_fatal() {
let msg = r#"Query execution failed: query returns error: Post "https://cloudcontrolapi.us-east-1.amazonaws.com/": dial tcp: lookup cloudcontrolapi.us-east-1.amazonaws.com on 8.8.4.4:53: i/o timeout"#;
assert!(check_fatal_error(msg).is_some());
}
#[test]
fn test_403_is_fatal() {
let msg = r#"http response status code: 403, response body: {"message":"Access Denied"}"#;
assert!(check_fatal_error(msg).is_some());
}
#[test]
fn test_401_is_fatal() {
let msg = r#"http response status code: 401, response body: {"message":"Unauthorized"}"#;
assert!(check_fatal_error(msg).is_some());
}
#[test]
fn test_404_is_not_fatal() {
let msg = r#"http response status code: 404, response body: {"__type":"ResourceNotFoundException","Message":"Resource not found"}"#;
assert!(check_fatal_error(msg).is_none());
}
#[test]
fn test_resource_not_found_is_not_fatal() {
let msg = r#"Resource of type 'AWS::EC2::VPC' with identifier 'vpc-xxx' was not found"#;
assert!(check_fatal_error(msg).is_none());
}
#[test]
fn test_400_bad_request_is_not_fatal() {
let msg = r#"insert over HTTP error: 400 Bad Request"#;
assert!(check_fatal_error(msg).is_none());
}
#[test]
fn test_normal_query_error_is_not_fatal() {
let msg = r#"query returns error: no such column: foo"#;
assert!(check_fatal_error(msg).is_none());
}
}