paper-gap 0.3.2

Local CLI for finding research papers with missing, weak, or stale public code
Documentation
use paper_gap::provider;
use reqwest::StatusCode;
use std::time::Duration;

#[test]
fn retries_only_transient_statuses() {
    for status in [
        StatusCode::TOO_MANY_REQUESTS,
        StatusCode::BAD_GATEWAY,
        StatusCode::SERVICE_UNAVAILABLE,
        StatusCode::GATEWAY_TIMEOUT,
    ] {
        assert!(provider::retry_delay(status, None).is_some());
    }
    for status in [
        StatusCode::BAD_REQUEST,
        StatusCode::UNAUTHORIZED,
        StatusCode::NOT_FOUND,
        StatusCode::INTERNAL_SERVER_ERROR,
    ] {
        assert_eq!(provider::retry_delay(status, None), None);
    }
}

#[test]
fn retry_after_is_parsed_and_capped() {
    assert_eq!(
        provider::retry_delay(StatusCode::TOO_MANY_REQUESTS, Some("2")),
        Some(Duration::from_secs(2))
    );
    assert_eq!(
        provider::retry_delay(StatusCode::TOO_MANY_REQUESTS, Some("60")),
        Some(Duration::from_secs(5))
    );
    assert_eq!(
        provider::retry_delay(StatusCode::TOO_MANY_REQUESTS, Some("invalid")),
        Some(Duration::from_millis(250))
    );
}

fn local_server(statuses: Vec<u16>) -> (String, std::thread::JoinHandle<()>) {
    use std::io::{Read, Write};
    let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
    let url = format!("http://{}", listener.local_addr().unwrap());
    let handle = std::thread::spawn(move || {
        for status in statuses {
            let (mut stream, _) = listener.accept().unwrap();
            let mut request = [0; 1024];
            let _ = stream.read(&mut request).unwrap();
            write!(
                stream,
                "HTTP/1.1 {status} test\r\nContent-Length: 0\r\nConnection: close\r\n\r\n"
            )
            .unwrap();
        }
    });
    (url, handle)
}

#[tokio::test]
async fn retries_transient_response_once_but_not_permanent_error() {
    let (url, server) = local_server(vec![503, 200]);
    let response = provider::send_with_retry(reqwest::Client::new().get(url))
        .await
        .unwrap();
    assert_eq!(response.status(), StatusCode::OK);
    server.join().unwrap();

    let (url, server) = local_server(vec![404]);
    let response = provider::send_with_retry(reqwest::Client::new().get(url))
        .await
        .unwrap();
    assert_eq!(response.status(), StatusCode::NOT_FOUND);
    server.join().unwrap();
}