use crate::protocol::{RequestContext, RequestRouteClass, StatusCode};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CacheAction {
CaptureArticle,
TrackAvailability,
TrackStat,
None,
}
#[inline]
fn should_capture_for_cache(
request: &RequestContext,
response_code: StatusCode,
cache_articles: bool,
has_message_id: bool,
) -> bool {
cache_articles
&& request.has_response_body(response_code)
&& has_message_id
&& matches!(response_code.as_u16(), 220 | 222)
}
#[inline]
pub fn should_track_availability(response_code: StatusCode, has_message_id: bool) -> bool {
has_message_id && matches!(response_code.as_u16(), 220..=223)
}
#[cfg(test)]
fn determine_cache_action(
command: &str,
response_code: u16,
cache_articles: bool,
has_message_id: bool,
) -> CacheAction {
let request = RequestContext::parse(command.as_bytes()).expect("valid request line");
let response_code = StatusCode::new(response_code);
determine_cache_action_for_request(&request, response_code, cache_articles, has_message_id)
}
pub fn determine_cache_action_for_request(
request: &RequestContext,
response_code: StatusCode,
cache_articles: bool,
has_message_id: bool,
) -> CacheAction {
debug_assert!(
!matches!(request.route_class(), RequestRouteClass::Stateful),
"stateful command in PerCommand path: {:?}",
request.kind()
);
if !has_message_id {
return CacheAction::None;
}
let has_response_body = request.has_response_body(response_code);
if should_capture_for_cache(request, response_code, cache_articles, has_message_id) {
CacheAction::CaptureArticle
} else if has_response_body && should_track_availability(response_code, has_message_id) {
CacheAction::TrackAvailability
} else if response_code.as_u16() == 223 {
CacheAction::TrackStat
} else {
CacheAction::None
}
}
#[cfg(test)]
mod tests {
use super::*;
fn request(command: &str) -> RequestContext {
RequestContext::parse(command.as_bytes()).expect("valid request line")
}
#[test]
fn test_should_capture_for_cache_article_response() {
assert!(should_capture_for_cache(
&request("ARTICLE <test@example.com>"),
StatusCode::new(220),
true,
true
));
assert!(should_capture_for_cache(
&request("BODY <test@example.com>"),
StatusCode::new(222),
true,
true
));
assert!(!should_capture_for_cache(
&request("HEAD <test@example.com>"),
StatusCode::new(221),
true,
true
));
}
#[test]
fn test_should_capture_for_cache_requires_all_conditions() {
assert!(!should_capture_for_cache(
&request("STAT <test@example.com>"),
StatusCode::new(220),
true,
true
));
assert!(!should_capture_for_cache(
&request("ARTICLE <test@example.com>"),
StatusCode::new(220),
false,
true
));
assert!(!should_capture_for_cache(
&request("ARTICLE <test@example.com>"),
StatusCode::new(220),
true,
false
));
assert!(!should_capture_for_cache(
&request("ARTICLE <test@example.com>"),
StatusCode::new(430),
true,
true
));
}
#[test]
fn test_should_capture_for_cache_220_and_222() {
assert!(should_capture_for_cache(
&request("ARTICLE <test@example.com>"),
StatusCode::new(220),
true,
true
));
assert!(should_capture_for_cache(
&request("BODY <test@example.com>"),
StatusCode::new(222),
true,
true
)); assert!(!should_capture_for_cache(
&request("HEAD <test@example.com>"),
StatusCode::new(221),
true,
true
)); assert!(!should_capture_for_cache(
&request("STAT <test@example.com>"),
StatusCode::new(223),
true,
true
)); }
#[test]
fn test_should_track_availability_success_responses() {
assert!(should_track_availability(StatusCode::new(220), true)); assert!(should_track_availability(StatusCode::new(221), true)); assert!(should_track_availability(StatusCode::new(222), true)); assert!(should_track_availability(StatusCode::new(223), true)); }
#[test]
fn test_should_track_availability_requires_message_id() {
assert!(!should_track_availability(StatusCode::new(220), false));
assert!(!should_track_availability(StatusCode::new(223), false));
}
#[test]
fn test_should_track_availability_error_responses() {
assert!(!should_track_availability(StatusCode::new(430), true)); assert!(!should_track_availability(StatusCode::new(500), true)); assert!(!should_track_availability(StatusCode::new(200), true)); }
#[test]
fn test_determine_cache_action_capture_article() {
assert_eq!(
determine_cache_action("ARTICLE <test@example.com>", 220, true, true),
CacheAction::CaptureArticle
);
}
#[test]
fn test_determine_cache_action_track_availability() {
assert_eq!(
determine_cache_action("HEAD <test@example.com>", 221, true, true),
CacheAction::TrackAvailability
);
assert_eq!(
determine_cache_action("BODY <test@example.com>", 222, true, true),
CacheAction::CaptureArticle
);
assert_eq!(
determine_cache_action("BODY <test@example.com>", 222, false, true),
CacheAction::TrackAvailability
);
}
#[test]
fn test_determine_cache_action_track_stat() {
assert_eq!(
determine_cache_action("STAT <test@example.com>", 223, true, true),
CacheAction::TrackStat
);
assert_eq!(
determine_cache_action("STAT <test@example.com>", 223, false, true),
CacheAction::TrackStat
);
}
#[test]
fn test_determine_cache_action_error_responses() {
assert_eq!(
determine_cache_action("ARTICLE <test@example.com>", 430, true, true),
CacheAction::None
);
assert_eq!(
determine_cache_action("ARTICLE <test@example.com>", 500, true, true),
CacheAction::None
);
}
#[test]
fn test_determine_cache_action_cache_disabled() {
assert_eq!(
determine_cache_action("ARTICLE <test@example.com>", 220, false, true),
CacheAction::TrackAvailability
);
}
}