Handle no-record cars and per-copy trash listing
Empty API responses (200 + empty body) mean "known car, no times
submitted yet" on the records site — typically newly released prize
cars. Previously each such car burned 3 retries with backoff and then
aborted the entire fetch; 27 cars in the current DB hit this.
- Add AppError::EmptyResponse { url } as a distinct, deterministic
failure class; get_file fails immediately instead of retrying
- fetch_car downgrades EmptyResponse to a skip with an info log, so
fetch completes; the next fetch picks the cars up automatically
once records exist
- parse_car_times treats empty (or whitespace-only) timing files
like missing files, eliminating "EOF while parsing a value at line
1 column 0" parse errors from stale empty files
trash.csv Config column now lists only the copies to delete: for a
car whose one tune is a final build not best on any track (e.g.
owned 332 next to a best-on-213-tracks 323), only the dead tune is
shown instead of joining all owned configs. Categories 1 and 3 still
list all configs since the whole car goes.
Tests: empty response makes exactly 1 request and yields the
EmptyResponse variant; empty file parses Ok; partial-copy trash
shows only the deletable config.
This commit is contained in:
parent
293a8d7707
commit
7ac889cbff
6 changed files with 148 additions and 45 deletions
|
|
@ -31,22 +31,23 @@ async fn test_get_file_success() {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_file_empty_response_retries_and_fails() {
|
||||
async fn test_get_file_empty_response_fails_immediately_without_retry() {
|
||||
let mut server = Server::new_async().await;
|
||||
// Return 200 with empty body — triggers retry, then fails
|
||||
let m = server
|
||||
.mock("GET", "/data.json")
|
||||
.with_status(200)
|
||||
.with_body("")
|
||||
.expect(4) // 1 initial + 3 retries
|
||||
.create();
|
||||
// 200 with empty body means "no data available yet" — permanent, so exactly
|
||||
// one request must be made (no retries) and a distinguishable error returned.
|
||||
let m = server.mock("GET", "/data.json").with_status(200).with_body("").expect(1).create();
|
||||
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let out_path = dir.path().join("output.txt");
|
||||
let url = format!("{}/data.json", server.url());
|
||||
|
||||
let result = get_file(&url, out_path.to_str().unwrap()).await;
|
||||
assert!(result.is_err(), "Empty response should fail after retries");
|
||||
let err = result.expect_err("Empty response should fail immediately");
|
||||
assert!(
|
||||
matches!(err, top_drives::AppError::EmptyResponse { .. }),
|
||||
"Empty response should yield AppError::EmptyResponse, got: {err}"
|
||||
);
|
||||
assert!(!out_path.exists(), "No file should be written for an empty response");
|
||||
m.assert();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue