Tests for push passes, downloads, OPML round trips and directory refresh
Each against a local stand-in server: Apple's push service answering per token, a feed host serving a login page and a torrent, a directory refresh of feeds that cannot be read. push.rs takes the APNs address as a parameter so the test can point it at the stand-in. coverage.sh asks for 8 GB free, not 9: its container is capped at 6. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RqkrVARreS9wxzH5o2rF7N
This commit is contained in:
@@ -217,4 +217,49 @@ mod tests {
|
||||
dir.pages_list.lock().await.as_mut().unwrap().0 -= PAGES_LIST_FOR;
|
||||
assert!(!Arc::ptr_eq(&first, &dir.pages_list().await.unwrap()));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn a_refresh_lists_a_feed_and_not_one_that_could_not_be_read() {
|
||||
use axum::routing::get;
|
||||
let rss = r#"<?xml version="1.0"?><rss version="2.0"><channel><title>Good Show</title>
|
||||
<item><title>One</title><guid>g1</guid><enclosure url="https://x/1.mp3" type="audio/mpeg" length="1"/></item>
|
||||
</channel></rss>"#;
|
||||
let opml =
|
||||
r#"<?xml version="1.0"?><opml version="2.0"><head/><body><outline xmlUrl="https://x/f"/></body></opml>"#;
|
||||
let app = axum::Router::new()
|
||||
.route("/good.xml", get(move || async move { rss }))
|
||||
.route("/list.opml", get(move || async move { opml }))
|
||||
.route("/garbled.xml", get(|| async { "<rss><channel" }))
|
||||
.route("/gone.xml", get(|| async { axum::http::StatusCode::NOT_FOUND }));
|
||||
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
|
||||
let at = listener.local_addr().unwrap();
|
||||
tokio::spawn(async move { axum::serve(listener, app).await });
|
||||
|
||||
let allowed = ipx_feed::guard::Allowed::parse(&["127.0.0.1".into()]).unwrap();
|
||||
let dir = Directory::new(Store::scratch().await, vec![], allowed).unwrap();
|
||||
let paths = ["/good.xml", "/list.opml", "/garbled.xml", "/gone.xml"];
|
||||
let entries: Vec<crate::SnapshotEntry> = paths
|
||||
.iter()
|
||||
.map(|p| crate::SnapshotEntry { url: format!("http://{at}{p}"), subscribers: 1, category: None })
|
||||
.collect();
|
||||
assert_eq!(dir.store.snapshot("tower", &entries).await.unwrap().accepted, 4);
|
||||
let due = dir.store.due(REFRESH_EVERY, 10).await.unwrap();
|
||||
assert_eq!(due.len(), 4);
|
||||
for d in &due {
|
||||
dir.refresh(d).await.unwrap();
|
||||
}
|
||||
assert!(dir.store.due(REFRESH_EVERY, 10).await.unwrap().is_empty(), "each was checked, failed or not");
|
||||
|
||||
let page = |path: &str| {
|
||||
let d = due.iter().find(|d| d.url.ends_with(path)).unwrap();
|
||||
dir.store.feed(&d.id)
|
||||
};
|
||||
let good = page("/good.xml").await.unwrap().unwrap();
|
||||
assert_eq!(good.listing.title.as_deref(), Some("Good Show"));
|
||||
assert!(good.listing.podcast && good.failing.is_none() && good.items.len() == 1);
|
||||
for bad in ["/list.opml", "/garbled.xml", "/gone.xml"] {
|
||||
// Never read, so never listed: a page of nothing is no use to anyone browsing.
|
||||
assert!(page(bad).await.unwrap().is_none(), "{bad} is not listed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user