fix: gate hard-fail attention on unsatisfied titles

This commit is contained in:
Miguel Palhas
2026-08-23 19:07:29 +01:00
parent 03e7774869
commit a28b455fff
+71 -1
View File
@@ -130,7 +130,8 @@ impl AttentionAction {
r#"
SELECT id AS "id!: i64", title AS "title!: String", year
FROM movies
WHERE (SELECT count(DISTINCT g.release_id)
WHERE movies.wanted = 1 AND movies.state != 'available'
AND (SELECT count(DISTINCT g.release_id)
FROM grabs g
WHERE g.target_kind = 'movie' AND g.target_id = movies.id
AND g.state = 'failed') >= 2
@@ -249,6 +250,7 @@ async fn queue_tv(database: &Db) -> Result<Vec<(i64, String, Option<i64>, TvEntr
JOIN seasons se ON se.id = e.season_id
JOIN series s ON s.id = se.series_id
WHERE g.state = 'failed'
AND e.wanted = 1 AND e.state != 'available'
GROUP BY s.id, s.title, s.year, e.id
HAVING count(DISTINCT g.release_id) >= 2
"#
@@ -561,4 +563,72 @@ mod tests {
"both hard-fail conditions roll up to one series notification"
);
}
#[tokio::test]
async fn a_movie_imported_after_two_hard_fails_leaves_the_queue() {
let (_dir, database) = seeded_database().await;
let movie_id = insert_no_pt_source_movie(&database).await;
insert_failed_grab(&database, "movie", movie_id, "first").await;
insert_failed_grab(&database, "movie", movie_id, "second").await;
let server = MockServer::start().await;
let action = action(&server).await;
let first = action.tick(&database).await.unwrap();
assert_eq!(first.len(), 1, "queued while unsatisfied");
// Imported from a third release: satisfied, no decision needed.
sqlx::query("UPDATE movies SET state = 'available' WHERE id = ?")
.bind(movie_id)
.execute(database.pool())
.await
.unwrap();
let second = action.tick(&database).await.unwrap();
assert_eq!(second.len(), 0, "leaves the queue once imported");
assert_eq!(server.received_requests().await.unwrap().len(), 1);
}
#[tokio::test]
async fn an_episode_imported_after_two_hard_fails_leaves_the_queue() {
let (_dir, database) = seeded_database().await;
insert_no_pt_source_series(&database, 1, 0).await;
let season_id: i64 = sqlx::query_scalar("SELECT id FROM seasons WHERE number = 1")
.fetch_one(database.pool())
.await
.unwrap();
sqlx::query(
"INSERT INTO episodes (season_id, number, title, wanted, state)
VALUES (?, 1, 'Episode 0', 1, 'missing')",
)
.bind(season_id)
.execute(database.pool())
.await
.unwrap();
let episode_id: i64 =
sqlx::query_scalar("SELECT id FROM episodes WHERE season_id = ? AND number = 1")
.bind(season_id)
.fetch_one(database.pool())
.await
.unwrap();
insert_failed_grab(&database, "episode", episode_id, "first").await;
insert_failed_grab(&database, "episode", episode_id, "second").await;
let server = MockServer::start().await;
let action = action(&server).await;
let first = action.tick(&database).await.unwrap();
assert_eq!(first.len(), 1, "queued while unsatisfied");
// Imported from a third release: satisfied, no decision needed.
sqlx::query("UPDATE episodes SET state = 'available' WHERE id = ?")
.bind(episode_id)
.execute(database.pool())
.await
.unwrap();
let second = action.tick(&database).await.unwrap();
assert_eq!(second.len(), 0, "leaves the queue once imported");
assert_eq!(server.received_requests().await.unwrap().len(), 1);
}
}