fix: real AP id tests, exact poster key check, exists port, list_movies fake

This commit is contained in:
2026-10-26 01:33:29 +01:00
parent 4cb2972f63
commit 818ab893a1
13 changed files with 395 additions and 80 deletions

View File

@@ -24,7 +24,7 @@ use domain::{
FakePosterFetcher, InMemoryStore, NoopEventPublisher, NoopObjectStorage, NoopPersonCommand,
test_movie_with_external_id,
},
value_objects::{ExternalMetadataId, MovieId, PosterUrl},
value_objects::{ExternalMetadataId, MovieId, PosterPath, PosterUrl},
};
use application::movies::{
@@ -239,6 +239,32 @@ impl domain::ports::ImageFetcher for NoImages {
}
}
/// Returns the key it was given, like the real adapter.
struct KeyStorage;
#[async_trait]
impl domain::ports::ObjectStorage for KeyStorage {
async fn store(&self, key: &str, _: &[u8]) -> Result<String, DomainError> {
Ok(key.to_string())
}
async fn get(&self, _: &str) -> Result<Vec<u8>, DomainError> {
Ok(vec![])
}
async fn get_stream(
&self,
_: &str,
) -> Result<futures::stream::BoxStream<'static, Result<bytes::Bytes, DomainError>>, DomainError>
{
Ok(Box::pin(futures::stream::empty()))
}
async fn delete(&self, _: &str) -> Result<(), DomainError> {
Ok(())
}
async fn exists(&self, _: &str) -> Result<bool, DomainError> {
Ok(true)
}
}
struct MetadataWithPoster;
#[async_trait]
@@ -409,7 +435,7 @@ async fn movie_discovery_indexer_is_idempotent_when_run_twice() {
#[tokio::test]
async fn search_reindex_is_idempotent_when_run_twice() {
let store = InMemoryStore::new();
seeded_movie(&store).await;
let (movie, _) = seeded_movie(&store).await;
let persons = FakePersons::new(person(3, "Someone"));
let search = RecordingSearch::new();
let handler = SearchReindexHandler::new(ReindexSearchDeps {
@@ -430,7 +456,11 @@ async fn search_reindex_is_idempotent_when_run_twice() {
.await
.unwrap();
assert!(!after_first.is_empty());
assert!(
after_first.contains(&("movie".to_string(), movie.id().value().to_string())),
"the movie doc is indexed"
);
assert!(after_first.iter().any(|(k, _)| k == "person"));
assert_eq!(search.snapshot(), after_first);
}
@@ -446,7 +476,7 @@ async fn poster_sync_is_idempotent_when_run_twice() {
store.clone(),
Arc::new(MetadataWithPoster),
Arc::new(FakePosterFetcher),
Arc::new(NoopObjectStorage),
Arc::new(KeyStorage),
publisher.clone(),
0,
);
@@ -466,3 +496,54 @@ async fn poster_sync_is_idempotent_when_run_twice() {
assert_eq!(synced, 1, "PosterSynced fans out to federation: emit once");
assert_eq!(publisher.published().len(), 1, "one ImageStored, not two");
}
#[tokio::test]
async fn poster_sync_skips_converted_poster_keys_but_not_lookalike_paths() {
let store = InMemoryStore::new();
let (mut movie, ext) = seeded_movie(&store).await;
let id = movie.id().value().to_string();
let publisher = NoopEventPublisher::new();
let handler = PosterSyncHandler::new(
store.clone(),
store.clone(),
Arc::new(MetadataWithPoster),
Arc::new(FakePosterFetcher),
Arc::new(KeyStorage),
publisher.clone(),
0,
);
let event = DomainEvent::MovieDiscovered {
movie_id: movie.id().clone(),
external_metadata_id: ext,
};
// The converter's output is the canonical synced key: skipped.
movie.update_poster(PosterPath::new(format!("{id}.webp")).unwrap());
store.upsert_movie(&movie, &[]).await.unwrap();
handler.handle(&event).await.unwrap();
assert!(publisher.published().is_empty());
// A foreign path that merely contains the id is not a synced poster.
movie.update_poster(PosterPath::new(format!("https://cdn.example/{id}/p.jpg")).unwrap());
store.upsert_movie(&movie, &[]).await.unwrap();
handler.handle(&event).await.unwrap();
assert_eq!(publisher.published().len(), 1);
}
#[tokio::test]
async fn enrichment_of_a_deleted_movie_stores_no_profile() {
let store = InMemoryStore::new();
let ghost = MovieId::from_uuid(uuid::Uuid::new_v4());
let search = RecordingSearch::new();
let client = Arc::new(CountingMovieClient(AtomicUsize::new(0)));
let handler = enrichment_handler(&store, client, search.clone());
let event = DomainEvent::MovieEnrichmentRequested {
movie_id: ghost.clone(),
external_metadata_id: ExternalMetadataId::new("tmdb:1".into()).unwrap(),
};
handler.handle(&event).await.unwrap();
assert!(store.get_by_movie_id(&ghost).await.unwrap().is_none());
assert!(search.snapshot().is_empty());
}