test: cascading in-memory store

This commit is contained in:
2026-10-25 22:19:24 +01:00
parent 51d92e08a7
commit 06eec2feae
72 changed files with 2439 additions and 1627 deletions

View File

@@ -1,7 +1,7 @@
use crate::test_support::{login_command, register_command};
use std::sync::Arc;
use domain::testing::InMemoryUserRepository;
use domain::testing::InMemoryStore;
use crate::{
auth::{
@@ -31,7 +31,7 @@ async fn setup_user(b: &TestContextBuilder, email: &str, password: &str) {
#[tokio::test]
async fn test_login_valid_credentials_returns_token() {
let users = InMemoryUserRepository::new();
let users = InMemoryStore::new();
let b = TestContextBuilder::new().with_users(Arc::clone(&users) as _);
setup_user(&b, "carol@example.com", "secret123").await;
@@ -53,7 +53,7 @@ async fn test_login_valid_credentials_returns_token() {
#[tokio::test]
async fn test_login_wrong_password_fails() {
let users = InMemoryUserRepository::new();
let users = InMemoryStore::new();
let b = TestContextBuilder::new().with_users(Arc::clone(&users) as _);
setup_user(&b, "dave@example.com", "correct_password").await;

View File

@@ -1,7 +1,7 @@
use crate::test_support::{login_command, register_command};
use std::sync::Arc;
use domain::testing::InMemoryUserRepository;
use domain::testing::InMemoryStore;
use crate::{
auth::{
@@ -13,7 +13,7 @@ use crate::{
#[tokio::test]
async fn logout_revokes_refresh_token() {
let users = InMemoryUserRepository::new();
let users = InMemoryStore::new();
let b = TestContextBuilder::new().with_users(Arc::clone(&users) as _);
let reg_deps = RegisterDeps {

View File

@@ -1,7 +1,7 @@
use crate::test_support::{login_command, register_command};
use std::sync::Arc;
use domain::testing::InMemoryUserRepository;
use domain::testing::InMemoryStore;
use crate::{
auth::{
@@ -38,7 +38,7 @@ async fn login_user(b: &TestContextBuilder) -> login::LoginResult {
#[tokio::test]
async fn refresh_returns_new_tokens() {
let users = InMemoryUserRepository::new();
let users = InMemoryStore::new();
let b = TestContextBuilder::new().with_users(Arc::clone(&users) as _);
let login_result = login_user(&b).await;
@@ -58,7 +58,7 @@ async fn refresh_returns_new_tokens() {
#[tokio::test]
async fn refresh_rotates_token_old_one_invalid() {
let users = InMemoryUserRepository::new();
let users = InMemoryStore::new();
let b = TestContextBuilder::new().with_users(Arc::clone(&users) as _);
let login_result = login_user(&b).await;
let old_token = login_result.refresh_token.clone();
@@ -76,7 +76,7 @@ async fn refresh_rotates_token_old_one_invalid() {
#[tokio::test]
async fn refresh_with_new_token_works() {
let users = InMemoryUserRepository::new();
let users = InMemoryStore::new();
let b = TestContextBuilder::new().with_users(Arc::clone(&users) as _);
let login_result = login_user(&b).await;

View File

@@ -2,7 +2,7 @@ use crate::test_support::register_command;
use std::sync::Arc;
use domain::ports::UserRepository;
use domain::testing::InMemoryUserRepository;
use domain::testing::InMemoryStore;
use domain::value_objects::Email;
use crate::{
@@ -16,7 +16,7 @@ fn cmd(email: &str) -> RegisterCommand {
#[tokio::test]
async fn test_register_creates_user() {
let users = InMemoryUserRepository::new();
let users = InMemoryStore::new();
let b = TestContextBuilder::new().with_users(Arc::clone(&users) as _);
let deps = RegisterDeps {
user: b.user_repo.clone(),
@@ -36,7 +36,7 @@ async fn test_register_creates_user() {
#[tokio::test]
async fn test_register_duplicate_email_fails() {
let users = InMemoryUserRepository::new();
let users = InMemoryStore::new();
let b = TestContextBuilder::new().with_users(Arc::clone(&users) as _);
let deps = RegisterDeps {
user: b.user_repo.clone(),

View File

@@ -3,9 +3,7 @@ use std::sync::Arc;
use domain::{
ports::{MovieCommand, MovieQuery, ReviewRepository},
testing::{
FakeDiaryQuery, InMemoryMovieRepository, InMemoryReviewRepository, NoopEventPublisher,
},
testing::{FakeDiaryQuery, InMemoryStore, NoopEventPublisher},
value_objects::{MovieId, UserId},
};
@@ -15,8 +13,8 @@ use crate::{
#[tokio::test]
async fn test_delete_review_removes_it() {
let movies = InMemoryMovieRepository::new();
let reviews = InMemoryReviewRepository::new();
let movies = InMemoryStore::new();
let reviews = Arc::clone(&movies);
let diary = FakeDiaryQuery::new();
let events = NoopEventPublisher::new();
@@ -45,7 +43,7 @@ async fn test_delete_review_removes_it() {
.await
.unwrap();
assert_eq!(reviews.count(), 0, "review should be deleted");
assert_eq!(reviews.review_count(), 0, "review should be deleted");
assert!(
movies.get_movie_by_id(movie.id()).await.unwrap().is_none(),
"movie should be deleted when no reviews remain"
@@ -54,9 +52,9 @@ async fn test_delete_review_removes_it() {
#[tokio::test]
async fn test_delete_review_wrong_user_is_unauthorized() {
let reviews = InMemoryReviewRepository::new();
let reviews = InMemoryStore::new();
let diary = FakeDiaryQuery::new();
let movies = InMemoryMovieRepository::new();
let movies = Arc::clone(&reviews);
let events = NoopEventPublisher::new();
let movie_id = MovieId::from_uuid(uuid::Uuid::new_v4());
@@ -83,5 +81,5 @@ async fn test_delete_review_wrong_user_is_unauthorized() {
.await;
assert!(result.is_err(), "wrong user should not be able to delete");
assert_eq!(reviews.count(), 1, "review should still exist");
assert_eq!(reviews.review_count(), 1, "review should still exist");
}

View File

@@ -4,19 +4,19 @@ use std::sync::Arc;
use domain::{
models::ReviewEdit,
ports::ReviewRepository,
testing::{InMemoryReviewRepository, NoopEventPublisher, test_review},
testing::{InMemoryStore, NoopEventPublisher, test_review},
value_objects::{Comment, MovieId, ReviewId, UserId, WatchMedium},
};
use crate::diary::{commands::EditReviewCommand, deps::EditReviewDeps, edit_review};
async fn setup() -> (
Arc<InMemoryReviewRepository>,
Arc<InMemoryStore>,
Arc<NoopEventPublisher>,
ReviewId,
UserId,
) {
let reviews = InMemoryReviewRepository::new();
let reviews = InMemoryStore::new();
let events = NoopEventPublisher::new();
let user_id = UserId::generate();
let review = test_review(&MovieId::generate(), &user_id, 3).apply_edit(ReviewEdit {
@@ -29,10 +29,7 @@ async fn setup() -> (
(reviews, events, review_id, user_id)
}
fn deps(
reviews: &Arc<InMemoryReviewRepository>,
events: &Arc<NoopEventPublisher>,
) -> EditReviewDeps {
fn deps(reviews: &Arc<InMemoryStore>, events: &Arc<NoopEventPublisher>) -> EditReviewDeps {
EditReviewDeps {
review: Arc::clone(reviews) as _,
event_publisher: Arc::clone(events) as _,
@@ -62,7 +59,7 @@ async fn edit_own_review_updates_rating() {
#[tokio::test]
async fn edit_nonexistent_review_returns_not_found() {
let reviews = InMemoryReviewRepository::new();
let reviews = InMemoryStore::new();
let events = NoopEventPublisher::new();
let err = edit_review::execute(&deps(&reviews, &events), edit_review_command(5))

View File

@@ -2,7 +2,7 @@ use std::sync::Arc;
use async_trait::async_trait;
use domain::errors::DomainError;
use domain::testing::InMemorySocialRepository;
use domain::testing::InMemoryStore;
use domain::value_objects::{FollowRelation, SocialActor, SocialIdentity, UserId};
use crate::{
@@ -13,7 +13,7 @@ use crate::{
fn default_deps() -> GetActivityFeedDeps {
GetActivityFeedDeps {
diary: domain::testing::FakeDiaryQuery::new() as _,
social_query: InMemorySocialRepository::new() as _,
social_query: InMemoryStore::new() as _,
config: TestContextBuilder::new().config,
}
}

View File

@@ -5,7 +5,7 @@ use uuid::Uuid;
use domain::{
ports::MovieCommand,
testing::{FakeDiaryQuery, InMemoryMovieProfileRepository, InMemoryMovieRepository},
testing::{FakeDiaryQuery, InMemoryStore},
};
use crate::{
@@ -16,9 +16,9 @@ use crate::{
#[tokio::test]
async fn fails_when_movie_not_found() {
let deps = GetMovieSocialPageDeps {
movie_query: InMemoryMovieRepository::new(),
movie_query: InMemoryStore::new(),
diary: FakeDiaryQuery::new() as _,
movie_profile: InMemoryMovieProfileRepository::new(),
movie_profile: InMemoryStore::new(),
};
let result = get_movie_social_page::execute(
@@ -36,7 +36,7 @@ async fn fails_when_movie_not_found() {
#[tokio::test]
async fn returns_movie_social_page() {
let movies = InMemoryMovieRepository::new();
let movies = InMemoryStore::new();
let movie = test_movie_with_year("Social Movie", 2024);
let movie_uuid = movie.id().value();
@@ -45,7 +45,7 @@ async fn returns_movie_social_page() {
let deps = GetMovieSocialPageDeps {
movie_query: Arc::clone(&movies) as _,
diary: FakeDiaryQuery::new() as _,
movie_profile: InMemoryMovieProfileRepository::new(),
movie_profile: InMemoryStore::new(),
};
let result = get_movie_social_page::execute(

View File

@@ -4,7 +4,7 @@ use std::sync::Arc;
use domain::ports::MovieCommand;
use domain::testing::{InMemoryMovieRepository, InMemoryReviewRepository, NoopEventPublisher};
use domain::testing::{InMemoryStore, NoopEventPublisher};
use crate::{
diary::commands::LogReviewCommand, diary::log_review,
@@ -12,8 +12,8 @@ use crate::{
};
fn build_logger(
movies: &Arc<InMemoryMovieRepository>,
reviews: &Arc<InMemoryReviewRepository>,
movies: &Arc<InMemoryStore>,
reviews: &Arc<InMemoryStore>,
events: &Arc<NoopEventPublisher>,
) -> Arc<dyn crate::ports::ReviewLogger> {
Arc::new(DefaultReviewLogger::new(
@@ -28,8 +28,8 @@ fn build_logger(
#[tokio::test]
async fn test_log_review_creates_movie_and_review() {
let movies = InMemoryMovieRepository::new();
let reviews = InMemoryReviewRepository::new();
let movies = InMemoryStore::new();
let reviews = Arc::clone(&movies);
let events = NoopEventPublisher::new();
let logger = build_logger(&movies, &reviews, &events);
@@ -38,14 +38,14 @@ async fn test_log_review_creates_movie_and_review() {
log_review::execute(&logger, cmd).await.unwrap();
assert_eq!(reviews.count(), 1, "review should be saved");
assert_eq!(reviews.review_count(), 1, "review should be saved");
assert!(!events.published().is_empty(), "events should be published");
}
#[tokio::test]
async fn test_log_review_reuses_existing_movie() {
let movies = InMemoryMovieRepository::new();
let reviews = InMemoryReviewRepository::new();
let movies = InMemoryStore::new();
let reviews = Arc::clone(&movies);
let existing_movie = test_movie_with_year("Alien", 1979);
let movie_uuid = existing_movie.id().value();
@@ -61,14 +61,14 @@ async fn test_log_review_reuses_existing_movie() {
log_review::execute(&logger, cmd).await.unwrap();
assert_eq!(movies.count(), 1, "no duplicate movie");
assert_eq!(reviews.count(), 1);
assert_eq!(movies.movie_count(), 1, "no duplicate movie");
assert_eq!(reviews.review_count(), 1);
}
#[tokio::test]
async fn test_log_review_with_invalid_rating_fails() {
let movies = InMemoryMovieRepository::new();
let reviews = InMemoryReviewRepository::new();
let movies = InMemoryStore::new();
let reviews = Arc::clone(&movies);
let events = NoopEventPublisher::new();
let logger = build_logger(&movies, &reviews, &events);

View File

@@ -8,10 +8,7 @@ use domain::{
models::WatchlistEntry,
models::{MetadataSearchCriteria, Movie},
ports::{MetadataClient, MovieCommand, WatchlistRepository},
testing::{
FakeMetadataClient, InMemoryMovieRepository, InMemoryReviewRepository,
InMemoryWatchlistRepository, NoopEventPublisher,
},
testing::{FakeMetadataClient, InMemoryStore, NoopEventPublisher},
value_objects::{ExternalMetadataId, MovieId, PosterUrl, UserId},
};
use uuid::Uuid;
@@ -21,9 +18,9 @@ use crate::diary::review_logger::DefaultReviewLogger;
use crate::ports::ReviewLogger;
fn make_logger(
movies: &Arc<InMemoryMovieRepository>,
reviews: &Arc<InMemoryReviewRepository>,
watchlist: &Arc<InMemoryWatchlistRepository>,
movies: &Arc<InMemoryStore>,
reviews: &Arc<InMemoryStore>,
watchlist: &Arc<InMemoryStore>,
events: &Arc<NoopEventPublisher>,
) -> DefaultReviewLogger {
DefaultReviewLogger::new(
@@ -38,9 +35,9 @@ fn make_logger(
#[tokio::test]
async fn logs_review_with_manual_movie() {
let movies = InMemoryMovieRepository::new();
let reviews = InMemoryReviewRepository::new();
let watchlist = InMemoryWatchlistRepository::new();
let movies = InMemoryStore::new();
let reviews = Arc::clone(&movies);
let watchlist = Arc::clone(&movies);
let events = NoopEventPublisher::new();
let logger = make_logger(&movies, &reviews, &watchlist, &events);
@@ -49,15 +46,15 @@ async fn logs_review_with_manual_movie() {
logger.log_review(cmd).await.unwrap();
assert_eq!(movies.count(), 1);
assert_eq!(reviews.count(), 1);
assert_eq!(movies.movie_count(), 1);
assert_eq!(reviews.review_count(), 1);
}
#[tokio::test]
async fn removes_from_watchlist_on_review() {
let movies = InMemoryMovieRepository::new();
let reviews = InMemoryReviewRepository::new();
let watchlist = InMemoryWatchlistRepository::new();
let movies = InMemoryStore::new();
let reviews = Arc::clone(&movies);
let watchlist = Arc::clone(&movies);
let events = NoopEventPublisher::new();
let logger = make_logger(&movies, &reviews, &watchlist, &events);
@@ -72,7 +69,7 @@ async fn removes_from_watchlist_on_review() {
// Add to watchlist
let entry = WatchlistEntry::new(user_id.clone(), MovieId::from_uuid(movie_id));
watchlist.add(&entry).await.unwrap();
assert_eq!(watchlist.count(), 1);
assert_eq!(watchlist.watchlist_count(), 1);
// Log review for same movie
let cmd = LogReviewCommand {
@@ -82,14 +79,14 @@ async fn removes_from_watchlist_on_review() {
logger.log_review(cmd).await.unwrap();
assert_eq!(watchlist.count(), 0);
assert_eq!(watchlist.watchlist_count(), 0);
}
#[tokio::test]
async fn logs_review_with_existing_movie_by_id() {
let movies = InMemoryMovieRepository::new();
let reviews = InMemoryReviewRepository::new();
let watchlist = InMemoryWatchlistRepository::new();
let movies = InMemoryStore::new();
let reviews = Arc::clone(&movies);
let watchlist = Arc::clone(&movies);
let events = NoopEventPublisher::new();
let logger = make_logger(&movies, &reviews, &watchlist, &events);
@@ -104,15 +101,15 @@ async fn logs_review_with_existing_movie_by_id() {
logger.log_review(cmd).await.unwrap();
assert_eq!(movies.count(), 1);
assert_eq!(reviews.count(), 1);
assert_eq!(movies.movie_count(), 1);
assert_eq!(reviews.review_count(), 1);
}
#[tokio::test]
async fn existing_movie_not_found_returns_error() {
let movies = InMemoryMovieRepository::new();
let reviews = InMemoryReviewRepository::new();
let watchlist = InMemoryWatchlistRepository::new();
let movies = InMemoryStore::new();
let reviews = Arc::clone(&movies);
let watchlist = Arc::clone(&movies);
let events = NoopEventPublisher::new();
let logger = make_logger(&movies, &reviews, &watchlist, &events);
@@ -123,9 +120,9 @@ async fn existing_movie_not_found_returns_error() {
#[tokio::test]
async fn invalid_rating_returns_error() {
let movies = InMemoryMovieRepository::new();
let reviews = InMemoryReviewRepository::new();
let watchlist = InMemoryWatchlistRepository::new();
let movies = InMemoryStore::new();
let reviews = Arc::clone(&movies);
let watchlist = Arc::clone(&movies);
let events = NoopEventPublisher::new();
let logger = make_logger(&movies, &reviews, &watchlist, &events);
@@ -137,15 +134,15 @@ async fn invalid_rating_returns_error() {
let result = logger.log_review(cmd).await;
assert!(result.is_err());
// No repo calls should have happened
assert_eq!(movies.count(), 0);
assert_eq!(reviews.count(), 0);
assert_eq!(movies.movie_count(), 0);
assert_eq!(reviews.review_count(), 0);
}
#[tokio::test]
async fn watchlist_not_present_does_not_publish_removed() {
let movies = InMemoryMovieRepository::new();
let reviews = InMemoryReviewRepository::new();
let watchlist = InMemoryWatchlistRepository::new();
let movies = InMemoryStore::new();
let reviews = Arc::clone(&movies);
let watchlist = Arc::clone(&movies);
let events = NoopEventPublisher::new();
let logger = make_logger(&movies, &reviews, &watchlist, &events);
@@ -187,9 +184,9 @@ impl MetadataClient for MetadataClientWithExternalId {
#[tokio::test]
async fn publishes_movie_discovered_for_new_movie_with_external_id() {
let movies = InMemoryMovieRepository::new();
let reviews = InMemoryReviewRepository::new();
let watchlist = InMemoryWatchlistRepository::new();
let movies = InMemoryStore::new();
let reviews = Arc::clone(&movies);
let watchlist = Arc::clone(&movies);
let events = NoopEventPublisher::new();
let logger = DefaultReviewLogger::new(

View File

@@ -2,7 +2,7 @@ use crate::test_support::create_goal_command;
use std::sync::Arc;
use domain::events::DomainEvent;
use domain::testing::{FakeStatsRepository, InMemoryGoalRepository, NoopEventPublisher};
use domain::testing::{FakeStatsRepository, InMemoryStore, NoopEventPublisher};
use uuid::Uuid;
use crate::goals::create;
@@ -11,7 +11,7 @@ use crate::test_helpers::TestContextBuilder;
#[tokio::test]
async fn creates_goal_and_returns_progress() {
let goals = InMemoryGoalRepository::new();
let goals = InMemoryStore::new();
let stats = FakeStatsRepository::new();
let events = NoopEventPublisher::new();
let deps = GoalCommandDeps {
@@ -28,12 +28,12 @@ async fn creates_goal_and_returns_progress() {
assert_eq!(result.goal.year(), 2025);
assert_eq!(result.goal.target_count(), 50);
assert_eq!(result.current_count, 0);
assert_eq!(goals.count(), 1);
assert_eq!(goals.goal_count(), 1);
}
#[tokio::test]
async fn creates_goal_with_review_count() {
let goals = InMemoryGoalRepository::new();
let goals = InMemoryStore::new();
let stats = FakeStatsRepository::new();
stats.set_review_count(Uuid::nil(), 2025, 5);
let events = NoopEventPublisher::new();
@@ -49,7 +49,7 @@ async fn creates_goal_with_review_count() {
.unwrap();
assert_eq!(result.current_count, 5);
assert_eq!(goals.count(), 1);
assert_eq!(goals.goal_count(), 1);
}
#[tokio::test]

View File

@@ -1,7 +1,7 @@
use crate::test_support::create_goal_command;
use std::sync::Arc;
use domain::testing::{FakeStatsRepository, InMemoryGoalRepository, NoopEventPublisher};
use domain::testing::{FakeStatsRepository, InMemoryStore, NoopEventPublisher};
use uuid::Uuid;
use crate::goals::deps::GoalCommandDeps;
@@ -10,7 +10,7 @@ use crate::test_helpers::TestContextBuilder;
#[tokio::test]
async fn deletes_existing_goal() {
let goals = InMemoryGoalRepository::new();
let goals = InMemoryStore::new();
let stats = FakeStatsRepository::new();
let events = NoopEventPublisher::new();
let deps = GoalCommandDeps {
@@ -23,7 +23,7 @@ async fn deletes_existing_goal() {
create::execute(&deps, create_goal_command(2025, 10))
.await
.unwrap();
assert_eq!(goals.count(), 1);
assert_eq!(goals.goal_count(), 1);
delete::execute(
&deps,
@@ -35,7 +35,7 @@ async fn deletes_existing_goal() {
.await
.unwrap();
assert_eq!(goals.count(), 0);
assert_eq!(goals.goal_count(), 0);
}
#[tokio::test]

View File

@@ -10,7 +10,7 @@ use domain::{
import::{ImportRow, ParsedFile, RowResult},
},
ports::{DocumentParser, MovieCommand},
testing::{InMemoryImportSessionRepository, InMemoryMovieRepository},
testing::InMemoryStore,
value_objects::ExternalMetadataId,
};
@@ -20,7 +20,7 @@ use crate::test_helpers::TestContextBuilder;
#[tokio::test]
async fn applies_mapping_to_session() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let b = TestContextBuilder::new();
let user_id = Uuid::new_v4();
@@ -54,7 +54,7 @@ async fn applies_mapping_to_session() {
#[tokio::test]
async fn fails_when_session_not_found() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let b = TestContextBuilder::new();
let deps = ApplyMappingDeps {
@@ -105,8 +105,8 @@ impl DocumentParser for DuplicateTestParser {
#[tokio::test]
async fn marks_duplicate_by_external_id() {
let movies = InMemoryMovieRepository::new();
let sessions = InMemoryImportSessionRepository::new();
let movies = InMemoryStore::new();
let sessions = Arc::clone(&movies);
let ext_id = ExternalMetadataId::new("tt1234567".into()).unwrap();
let movie = test_movie_with_external_id("Known Movie", 2020, ext_id);
@@ -154,8 +154,8 @@ async fn marks_duplicate_by_external_id() {
#[tokio::test]
async fn marks_duplicate_by_title_and_year() {
let movies = InMemoryMovieRepository::new();
let sessions = InMemoryImportSessionRepository::new();
let movies = InMemoryStore::new();
let sessions = Arc::clone(&movies);
let movie = test_movie_with_year("Duplicate Film", 2022);
movies.upsert_movie(&movie).await.unwrap();

View File

@@ -4,7 +4,7 @@ use std::sync::Arc;
use chrono::Utc;
use domain::models::ImportProfile;
use domain::ports::{ImportProfileRepository, ImportSessionRepository};
use domain::testing::{InMemoryImportProfileRepository, InMemoryImportSessionRepository};
use domain::testing::InMemoryStore;
use domain::value_objects::{ImportProfileId, UserId};
use uuid::Uuid;
@@ -13,8 +13,8 @@ use crate::import::deps::ApplyProfileDeps;
#[tokio::test]
async fn fails_when_profile_not_found() {
let profiles = InMemoryImportProfileRepository::new();
let sessions = InMemoryImportSessionRepository::new();
let profiles = InMemoryStore::new();
let sessions = Arc::clone(&profiles);
let deps = ApplyProfileDeps {
import_profile: Arc::clone(&profiles) as _,
@@ -32,8 +32,8 @@ async fn fails_when_profile_not_found() {
#[tokio::test]
async fn fails_when_session_not_found() {
let profiles = InMemoryImportProfileRepository::new();
let sessions = InMemoryImportSessionRepository::new();
let profiles = InMemoryStore::new();
let sessions = Arc::clone(&profiles);
let user_id = Uuid::new_v4();
let profile = ImportProfile::new(
@@ -62,8 +62,8 @@ async fn fails_when_session_not_found() {
#[tokio::test]
async fn applies_profile_mappings_to_session() {
let profiles = InMemoryImportProfileRepository::new();
let sessions = domain::testing::InMemoryImportSessionRepository::new();
let profiles = InMemoryStore::new();
let sessions = domain::testing::InMemoryStore::new();
let user_id = Uuid::new_v4();
let profile = ImportProfile::new(
@@ -97,11 +97,11 @@ async fn applies_profile_mappings_to_session() {
.unwrap();
// Verify the session got updated with field_mappings and row_results cleared
let updated = sessions
.get(&session_id, &UserId::from_uuid(user_id))
.await
.unwrap()
.unwrap();
let updated =
ImportSessionRepository::get(&*sessions, &session_id, &UserId::from_uuid(user_id))
.await
.unwrap()
.unwrap();
assert!(updated.field_mappings.is_some());
assert_eq!(updated.field_mappings.unwrap().len(), 1);
assert!(updated.row_results.is_none());

View File

@@ -7,7 +7,7 @@ use uuid::Uuid;
use domain::models::import::{DomainField, Transform};
use domain::models::{FieldMapping, ImportProfile};
use domain::ports::{ImportProfileRepository, ImportSessionRepository};
use domain::testing::{InMemoryImportProfileRepository, InMemoryImportSessionRepository};
use domain::testing::InMemoryStore;
use domain::value_objects::{ImportProfileId, UserId};
use crate::import::deps::{ApplyProfileAndMapDeps, CreateSessionDeps};
@@ -16,8 +16,8 @@ use crate::test_helpers::TestContextBuilder;
#[tokio::test]
async fn fails_when_profile_not_found() {
let profiles = InMemoryImportProfileRepository::new();
let sessions = InMemoryImportSessionRepository::new();
let profiles = InMemoryStore::new();
let sessions = Arc::clone(&profiles);
let b = TestContextBuilder::new();
let deps = ApplyProfileAndMapDeps {
@@ -42,8 +42,8 @@ async fn fails_when_profile_not_found() {
#[tokio::test]
async fn applies_profile_then_regenerates_mapping() {
let profiles = InMemoryImportProfileRepository::new();
let sessions = InMemoryImportSessionRepository::new();
let profiles = InMemoryStore::new();
let sessions = Arc::clone(&profiles);
let b = TestContextBuilder::new();
let user_id = Uuid::new_v4();
@@ -92,11 +92,11 @@ async fn applies_profile_then_regenerates_mapping() {
assert!(!rows.is_empty());
let updated = sessions
.get(&created.session_id, &UserId::from_uuid(user_id))
.await
.unwrap()
.unwrap();
let updated =
ImportSessionRepository::get(&*sessions, &created.session_id, &UserId::from_uuid(user_id))
.await
.unwrap()
.unwrap();
assert!(updated.row_results.is_some());
assert!(updated.field_mappings.is_some());
}

View File

@@ -1,12 +1,12 @@
use std::sync::Arc;
use domain::testing::InMemoryImportSessionRepository;
use domain::testing::InMemoryStore;
use crate::import::cleanup;
#[tokio::test]
async fn returns_zero_when_nothing_expired() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let result = cleanup::execute(Arc::clone(&sessions) as _).await.unwrap();

View File

@@ -3,7 +3,7 @@ use std::sync::Arc;
use uuid::Uuid;
use domain::testing::InMemoryImportSessionRepository;
use domain::testing::InMemoryStore;
use crate::import::create_session;
use crate::import::deps::CreateSessionDeps;
@@ -11,7 +11,7 @@ use crate::test_helpers::TestContextBuilder;
#[tokio::test]
async fn creates_session_with_parsed_file() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let b = TestContextBuilder::new();
let deps = CreateSessionDeps {

View File

@@ -1,6 +1,6 @@
use std::sync::Arc;
use domain::testing::InMemoryImportProfileRepository;
use domain::testing::InMemoryStore;
use uuid::Uuid;
use crate::import::{
@@ -9,7 +9,7 @@ use crate::import::{
#[tokio::test]
async fn fails_when_profile_not_found() {
let profiles = InMemoryImportProfileRepository::new();
let profiles = InMemoryStore::new();
let deps = DeleteImportProfileDeps {
import_profile: Arc::clone(&profiles) as _,
};

View File

@@ -3,7 +3,7 @@ use std::sync::Arc;
use domain::models::{AnnotatedRow, ImportSession, import::RowResult};
use domain::ports::ImportSessionRepository;
use domain::testing::InMemoryImportSessionRepository;
use domain::testing::InMemoryStore;
use domain::value_objects::UserId;
use uuid::Uuid;
@@ -45,7 +45,7 @@ fn make_session_with_rows(user_id: UserId) -> ImportSession {
#[tokio::test]
async fn imports_confirmed_rows() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let uid = Uuid::new_v4();
let session = make_session_with_rows(UserId::from_uuid(uid));
@@ -74,7 +74,7 @@ async fn imports_confirmed_rows() {
#[tokio::test]
async fn skips_unconfirmed_rows() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let uid = Uuid::new_v4();
let session = make_session_with_rows(UserId::from_uuid(uid));
@@ -96,7 +96,7 @@ async fn skips_unconfirmed_rows() {
#[tokio::test]
async fn fails_when_session_not_found() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let deps = ExecuteImportDeps {
import_session: Arc::clone(&sessions) as _,
@@ -117,7 +117,7 @@ async fn fails_when_session_not_found() {
#[tokio::test]
async fn handles_datetime_format() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let uid = Uuid::new_v4();
let mut session = ImportSession::new(UserId::from_uuid(uid));
@@ -151,7 +151,7 @@ async fn handles_datetime_format() {
#[tokio::test]
async fn fails_on_invalid_rating() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let uid = Uuid::new_v4();
let mut session = ImportSession::new(UserId::from_uuid(uid));
@@ -185,7 +185,7 @@ async fn fails_on_invalid_rating() {
#[tokio::test]
async fn fails_on_missing_watched_at() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let uid = Uuid::new_v4();
let mut session = ImportSession::new(UserId::from_uuid(uid));
@@ -219,7 +219,7 @@ async fn fails_on_missing_watched_at() {
#[tokio::test]
async fn imports_row_with_external_metadata_id() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let uid = Uuid::new_v4();
let mut session = ImportSession::new(UserId::from_uuid(uid));
@@ -253,7 +253,7 @@ async fn imports_row_with_external_metadata_id() {
#[tokio::test]
async fn imports_row_with_director_and_comment() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let uid = Uuid::new_v4();
let mut session = ImportSession::new(UserId::from_uuid(uid));
@@ -287,7 +287,7 @@ async fn imports_row_with_director_and_comment() {
#[tokio::test]
async fn handles_space_separated_datetime_format() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let uid = Uuid::new_v4();
let mut session = ImportSession::new(UserId::from_uuid(uid));
@@ -321,7 +321,7 @@ async fn handles_space_separated_datetime_format() {
#[tokio::test]
async fn reports_invalid_row_result_errors() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let uid = Uuid::new_v4();
let mut session = ImportSession::new(UserId::from_uuid(uid));
@@ -352,7 +352,7 @@ async fn reports_invalid_row_result_errors() {
#[tokio::test]
async fn fails_on_missing_rating() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let uid = Uuid::new_v4();
let mut session = ImportSession::new(UserId::from_uuid(uid));
@@ -387,7 +387,7 @@ async fn fails_on_missing_rating() {
#[tokio::test]
async fn fails_on_unparseable_date() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let uid = Uuid::new_v4();
let mut session = ImportSession::new(UserId::from_uuid(uid));
@@ -422,7 +422,7 @@ async fn fails_on_unparseable_date() {
#[tokio::test]
async fn imports_row_without_release_year() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let uid = Uuid::new_v4();
let mut session = ImportSession::new(UserId::from_uuid(uid));
@@ -456,13 +456,13 @@ async fn imports_row_without_release_year() {
#[tokio::test]
async fn deletes_session_after_import() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let uid = Uuid::new_v4();
let session = make_session_with_rows(UserId::from_uuid(uid));
let sid = session.id.clone();
sessions.create(&session).await.unwrap();
assert_eq!(sessions.count(), 1);
assert_eq!(sessions.import_session_count(), 1);
let deps = ExecuteImportDeps {
import_session: Arc::clone(&sessions) as _,
@@ -474,7 +474,7 @@ async fn deletes_session_after_import() {
.unwrap();
assert_eq!(
sessions.count(),
sessions.import_session_count(),
0,
"session should be deleted after import"
);
@@ -482,7 +482,7 @@ async fn deletes_session_after_import() {
#[tokio::test]
async fn imports_more_rows_than_concurrency_limit() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let uid = Uuid::new_v4();
let rows: Vec<_> = (0..15)

View File

@@ -5,7 +5,7 @@ use uuid::Uuid;
use domain::models::ImportSession;
use domain::models::import::ParsedFile;
use domain::ports::ImportSessionRepository;
use domain::testing::InMemoryImportSessionRepository;
use domain::testing::InMemoryStore;
use domain::value_objects::{ImportSessionId, UserId};
use crate::import::deps::GetMappingStageDeps;
@@ -13,7 +13,7 @@ use crate::import::get_mapping_stage::{self, SAMPLE_ROW_LIMIT};
#[tokio::test]
async fn get_mapping_stage_is_not_found_when_file_not_parsed() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let user_id = Uuid::new_v4();
let session = ImportSession::new(UserId::from_uuid(user_id));
let session_id = session.id.clone();
@@ -30,7 +30,7 @@ async fn get_mapping_stage_is_not_found_when_file_not_parsed() {
#[tokio::test]
async fn get_mapping_stage_is_not_found_when_session_missing() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let deps = GetMappingStageDeps {
import_session: Arc::clone(&sessions) as _,
};
@@ -43,7 +43,7 @@ async fn get_mapping_stage_is_not_found_when_session_missing() {
#[tokio::test]
async fn get_mapping_stage_returns_columns_and_capped_sample_rows() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let user_id = Uuid::new_v4();
let mut session = ImportSession::new(UserId::from_uuid(user_id));
session.parsed_file = Some(ParsedFile {

View File

@@ -5,7 +5,7 @@ use uuid::Uuid;
use domain::models::import::{ImportRow, ParsedFile, RowResult};
use domain::models::{AnnotatedRow, ImportSession};
use domain::ports::ImportSessionRepository;
use domain::testing::InMemoryImportSessionRepository;
use domain::testing::InMemoryStore;
use domain::value_objects::{ImportSessionId, UserId};
use crate::import::deps::GetPreviewStageDeps;
@@ -13,7 +13,7 @@ use crate::import::get_preview_stage::{self, PreviewStage};
#[tokio::test]
async fn get_preview_stage_reports_not_yet_mapped_when_row_results_absent() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let user_id = Uuid::new_v4();
let session = ImportSession::new(UserId::from_uuid(user_id));
let session_id = session.id.clone();
@@ -32,7 +32,7 @@ async fn get_preview_stage_reports_not_yet_mapped_when_row_results_absent() {
#[tokio::test]
async fn get_preview_stage_returns_rows_once_mapped() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let user_id = Uuid::new_v4();
let mut session = ImportSession::new(UserId::from_uuid(user_id));
session.parsed_file = Some(ParsedFile {
@@ -68,7 +68,7 @@ async fn get_preview_stage_returns_rows_once_mapped() {
#[tokio::test]
async fn get_preview_stage_is_not_found_when_session_missing() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let deps = GetPreviewStageDeps {
import_session: Arc::clone(&sessions) as _,
};

View File

@@ -5,7 +5,7 @@ use uuid::Uuid;
use domain::models::ImportSession;
use domain::models::import::ParsedFile;
use domain::ports::ImportSessionRepository;
use domain::testing::InMemoryImportSessionRepository;
use domain::testing::InMemoryStore;
use domain::value_objects::{ImportSessionId, UserId};
use crate::import::deps::GetSessionStateDeps;
@@ -13,7 +13,7 @@ use crate::import::get_session_state;
#[tokio::test]
async fn get_session_state_is_not_found_when_session_missing() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let deps = GetSessionStateDeps {
import_session: Arc::clone(&sessions) as _,
};
@@ -26,7 +26,7 @@ async fn get_session_state_is_not_found_when_session_missing() {
#[tokio::test]
async fn get_session_state_reports_columns_row_count_and_mapping_status() {
let sessions = InMemoryImportSessionRepository::new();
let sessions = InMemoryStore::new();
let user_id = Uuid::new_v4();
let mut session = ImportSession::new(UserId::from_uuid(user_id));
session.parsed_file = Some(ParsedFile {

View File

@@ -1,6 +1,6 @@
use std::sync::Arc;
use domain::testing::InMemoryImportProfileRepository;
use domain::testing::InMemoryStore;
use domain::value_objects::UserId;
use uuid::Uuid;
@@ -8,7 +8,7 @@ use crate::import::{deps::ListImportProfilesDeps, list_profiles};
#[tokio::test]
async fn returns_empty_when_no_profiles() {
let profiles = InMemoryImportProfileRepository::new();
let profiles = InMemoryStore::new();
let deps = ListImportProfilesDeps {
import_profile: Arc::clone(&profiles) as _,
};

View File

@@ -2,7 +2,7 @@ use std::sync::Arc;
use domain::models::ImportSession;
use domain::ports::ImportSessionRepository;
use domain::testing::{InMemoryImportProfileRepository, InMemoryImportSessionRepository};
use domain::testing::InMemoryStore;
use domain::value_objects::UserId;
use uuid::Uuid;
@@ -11,8 +11,8 @@ use crate::import::{commands::SaveImportProfileCommand, save_profile};
#[tokio::test]
async fn fails_when_session_not_found() {
let sessions = InMemoryImportSessionRepository::new();
let profiles = InMemoryImportProfileRepository::new();
let sessions = InMemoryStore::new();
let profiles = Arc::clone(&sessions);
let deps = SaveProfileDeps {
import_session: Arc::clone(&sessions) as _,
@@ -34,8 +34,8 @@ async fn fails_when_session_not_found() {
#[tokio::test]
async fn saves_profile_from_session() {
let sessions = InMemoryImportSessionRepository::new();
let profiles = InMemoryImportProfileRepository::new();
let sessions = InMemoryStore::new();
let profiles = Arc::clone(&sessions);
let user_id = Uuid::new_v4();
let mut session = ImportSession::new(UserId::from_uuid(user_id));

View File

@@ -1,10 +1,10 @@
use domain::testing::InMemoryWatchEventRepository;
use domain::testing::InMemoryStore;
use crate::integrations::cleanup;
#[tokio::test]
async fn returns_zero_when_nothing_to_clean() {
let watch_events = InMemoryWatchEventRepository::new();
let watch_events = InMemoryStore::new();
let count = cleanup::execute(watch_events).await.unwrap();

View File

@@ -3,7 +3,7 @@ use std::sync::Arc;
use domain::models::{WatchEvent, WatchEventSource};
use domain::ports::{MovieCommand, WatchEventCommand};
use domain::testing::{InMemoryWatchEventRepository, NoopEventPublisher};
use domain::testing::{InMemoryStore, NoopEventPublisher};
use domain::value_objects::UserId;
use uuid::Uuid;
@@ -17,7 +17,7 @@ fn noop_logger() -> Arc<dyn crate::ports::ReviewLogger> {
}
fn deps(
watch_events: &Arc<InMemoryWatchEventRepository>,
watch_events: &Arc<InMemoryStore>,
review_logger: Arc<dyn crate::ports::ReviewLogger>,
) -> ConfirmWatchEventsDeps {
ConfirmWatchEventsDeps {
@@ -29,7 +29,7 @@ fn deps(
#[tokio::test]
async fn confirms_watch_event_via_review_logger() {
let watch_events = InMemoryWatchEventRepository::new();
let watch_events = InMemoryStore::new();
let uid = Uuid::new_v4();
let event = WatchEvent::new(
@@ -56,7 +56,7 @@ async fn confirms_watch_event_via_review_logger() {
#[tokio::test]
async fn empty_confirmations_returns_zero() {
let watch_events = InMemoryWatchEventRepository::new();
let watch_events = InMemoryStore::new();
let result = confirm::execute(
&deps(&watch_events, noop_logger()),
@@ -73,7 +73,7 @@ async fn empty_confirmations_returns_zero() {
#[tokio::test]
async fn confirms_event_with_external_metadata_id_and_no_movie_id() {
let watch_events = InMemoryWatchEventRepository::new();
let watch_events = InMemoryStore::new();
let uid = Uuid::new_v4();
let event = WatchEvent::new(
@@ -107,7 +107,7 @@ async fn confirms_event_with_external_metadata_id_and_no_movie_id() {
#[tokio::test]
async fn rejects_other_users_event() {
let watch_events = InMemoryWatchEventRepository::new();
let watch_events = InMemoryStore::new();
let owner = Uuid::new_v4();
let intruder = Uuid::new_v4();
@@ -134,7 +134,7 @@ async fn rejects_other_users_event() {
#[tokio::test]
async fn fails_when_event_not_found() {
let watch_events = InMemoryWatchEventRepository::new();
let watch_events = InMemoryStore::new();
let result = confirm::execute(
&deps(&watch_events, noop_logger()),
@@ -147,7 +147,7 @@ async fn fails_when_event_not_found() {
#[tokio::test]
async fn confirms_event_with_movie_id() {
let watch_events = InMemoryWatchEventRepository::new();
let watch_events = InMemoryStore::new();
let events = NoopEventPublisher::new();
let uid = Uuid::new_v4();
let movie_uuid = Uuid::new_v4();
@@ -165,7 +165,7 @@ async fn confirms_event_with_movie_id() {
watch_events.save(&event).await.unwrap();
// Also seed movie repo so review_logger can find it
let movies = domain::testing::InMemoryMovieRepository::new();
let movies = domain::testing::InMemoryStore::new();
let movie = domain::models::Movie::from_persistence(
domain::value_objects::MovieId::from_uuid(movie_uuid),
None,
@@ -177,8 +177,8 @@ async fn confirms_event_with_movie_id() {
movies.upsert_movie(&movie).await.unwrap();
// Build a real review logger
let reviews = domain::testing::InMemoryReviewRepository::new();
let watchlist = domain::testing::InMemoryWatchlistRepository::new();
let reviews = domain::testing::InMemoryStore::new();
let watchlist = domain::testing::InMemoryStore::new();
let review_logger: Arc<dyn crate::ports::ReviewLogger> =
Arc::new(crate::diary::review_logger::DefaultReviewLogger::new(
Arc::clone(&movies) as _,
@@ -201,7 +201,7 @@ async fn confirms_event_with_movie_id() {
#[tokio::test]
async fn confirms_event_without_movie_id_and_without_external_metadata_id() {
let watch_events = InMemoryWatchEventRepository::new();
let watch_events = InMemoryStore::new();
let uid = Uuid::new_v4();
let event = WatchEvent::new(
@@ -235,7 +235,7 @@ async fn confirms_event_without_movie_id_and_without_external_metadata_id() {
#[tokio::test]
async fn confirms_multiple_events() {
let watch_events = InMemoryWatchEventRepository::new();
let watch_events = InMemoryStore::new();
let uid = Uuid::new_v4();
let event1 = WatchEvent::new(
@@ -289,7 +289,7 @@ async fn confirms_multiple_events() {
#[tokio::test]
async fn confirms_event_without_year() {
let watch_events = InMemoryWatchEventRepository::new();
let watch_events = InMemoryStore::new();
let uid = Uuid::new_v4();
let event = WatchEvent::new(

View File

@@ -3,14 +3,14 @@ use std::sync::Arc;
use domain::models::{WatchEvent, WatchEventSource};
use domain::ports::WatchEventCommand;
use domain::testing::InMemoryWatchEventRepository;
use domain::testing::InMemoryStore;
use domain::value_objects::UserId;
use uuid::Uuid;
use crate::integrations::deps::DismissWatchEventsDeps;
use crate::integrations::dismiss;
fn deps(watch_events: &Arc<InMemoryWatchEventRepository>) -> DismissWatchEventsDeps {
fn deps(watch_events: &Arc<InMemoryStore>) -> DismissWatchEventsDeps {
DismissWatchEventsDeps {
watch_event_command: Arc::clone(watch_events) as _,
watch_event_query: Arc::clone(watch_events) as _,
@@ -19,7 +19,7 @@ fn deps(watch_events: &Arc<InMemoryWatchEventRepository>) -> DismissWatchEventsD
#[tokio::test]
async fn dismisses_empty_list_returns_zero() {
let events = InMemoryWatchEventRepository::new();
let events = InMemoryStore::new();
let result = dismiss::execute(
&deps(&events),
@@ -33,7 +33,7 @@ async fn dismisses_empty_list_returns_zero() {
#[tokio::test]
async fn fails_when_event_not_found() {
let events = InMemoryWatchEventRepository::new();
let events = InMemoryStore::new();
let result = dismiss::execute(
&deps(&events),
@@ -46,7 +46,7 @@ async fn fails_when_event_not_found() {
#[tokio::test]
async fn dismisses_existing_events() {
let watch_events = InMemoryWatchEventRepository::new();
let watch_events = InMemoryStore::new();
let uid = Uuid::new_v4();
let user_id = UserId::from_uuid(uid);

View File

@@ -2,7 +2,7 @@ use crate::test_support::generate_webhook_token_command;
use std::sync::Arc;
use domain::ports::WebhookTokenRepository;
use domain::testing::InMemoryWebhookTokenRepository;
use domain::testing::InMemoryStore;
use uuid::Uuid;
use crate::integrations::deps::GenerateWebhookTokenDeps;
@@ -10,7 +10,7 @@ use crate::integrations::generate_token;
#[tokio::test]
async fn generates_token_and_saves() {
let tokens: Arc<dyn WebhookTokenRepository> = InMemoryWebhookTokenRepository::new();
let tokens: Arc<dyn WebhookTokenRepository> = InMemoryStore::new();
let user_id = Uuid::new_v4();
let result = generate_token::execute(

View File

@@ -3,14 +3,14 @@ use std::sync::Arc;
use chrono::Utc;
use domain::models::{WatchEvent, WatchEventSource};
use domain::ports::WatchEventCommand;
use domain::testing::InMemoryWatchEventRepository;
use domain::testing::InMemoryStore;
use domain::value_objects::UserId;
use uuid::Uuid;
use crate::integrations::deps::GetWatchQueueDeps;
use crate::integrations::{get_queue, queries::GetWatchQueueQuery};
fn deps(events: &Arc<InMemoryWatchEventRepository>) -> GetWatchQueueDeps {
fn deps(events: &Arc<InMemoryStore>) -> GetWatchQueueDeps {
GetWatchQueueDeps {
watch_event_query: Arc::clone(events) as _,
}
@@ -18,7 +18,7 @@ fn deps(events: &Arc<InMemoryWatchEventRepository>) -> GetWatchQueueDeps {
#[tokio::test]
async fn returns_empty_when_no_events() {
let events = InMemoryWatchEventRepository::new();
let events = InMemoryStore::new();
let result = get_queue::execute(
&deps(&events),
@@ -34,7 +34,7 @@ async fn returns_empty_when_no_events() {
#[tokio::test]
async fn returns_pending_events() {
let events = InMemoryWatchEventRepository::new();
let events = InMemoryStore::new();
let user_id = Uuid::new_v4();
let event = WatchEvent::new(

View File

@@ -3,7 +3,7 @@ use std::sync::Arc;
use domain::models::WatchEventSource;
use domain::ports::WebhookTokenRepository;
use domain::testing::InMemoryWebhookTokenRepository;
use domain::testing::InMemoryStore;
use uuid::Uuid;
use crate::integrations::deps::{GenerateWebhookTokenDeps, GetWebhookTokensDeps};
@@ -26,7 +26,7 @@ fn get_deps(tokens: &Arc<dyn WebhookTokenRepository>) -> GetWebhookTokensDeps {
#[tokio::test]
async fn returns_empty_when_no_tokens() {
let tokens: Arc<dyn WebhookTokenRepository> = InMemoryWebhookTokenRepository::new();
let tokens: Arc<dyn WebhookTokenRepository> = InMemoryStore::new();
let result = get_tokens::execute(
&get_deps(&tokens),
@@ -42,7 +42,7 @@ async fn returns_empty_when_no_tokens() {
#[tokio::test]
async fn returns_tokens_after_generate() {
let tokens: Arc<dyn WebhookTokenRepository> = InMemoryWebhookTokenRepository::new();
let tokens: Arc<dyn WebhookTokenRepository> = InMemoryStore::new();
let user_id = Uuid::new_v4();

View File

@@ -2,10 +2,8 @@ use crate::test_support::generate_webhook_token_command;
use std::sync::Arc;
use domain::models::WatchEventSource;
use domain::ports::{EventPublisher, WebhookTokenRepository};
use domain::testing::{
InMemoryWatchEventRepository, InMemoryWebhookTokenRepository, NoopEventPublisher,
};
use domain::ports::EventPublisher;
use domain::testing::{InMemoryStore, NoopEventPublisher};
use uuid::Uuid;
use crate::integrations::commands::IngestWatchEventCommand;
@@ -30,14 +28,14 @@ impl domain::ports::MediaServerParser for FakeParser {
#[tokio::test]
async fn ingests_watch_event() {
let tokens: Arc<dyn WebhookTokenRepository> = InMemoryWebhookTokenRepository::new();
let watch_events = InMemoryWatchEventRepository::new();
let tokens = InMemoryStore::new();
let watch_events = Arc::clone(&tokens);
let event_publisher: Arc<dyn EventPublisher> = NoopEventPublisher::new();
let user_id = Uuid::new_v4();
let generated = generate_token::execute(
&GenerateWebhookTokenDeps {
webhook_token: Arc::clone(&tokens),
webhook_token: Arc::clone(&tokens) as _,
},
generate_webhook_token_command(user_id),
)
@@ -45,7 +43,7 @@ async fn ingests_watch_event() {
.unwrap();
let deps = IngestWatchEventDeps {
webhook_token: Arc::clone(&tokens),
webhook_token: Arc::clone(&tokens) as _,
watch_event_command: Arc::clone(&watch_events) as _,
watch_event_query: Arc::clone(&watch_events) as _,
event_publisher: Arc::clone(&event_publisher),
@@ -67,12 +65,12 @@ async fn ingests_watch_event() {
#[tokio::test]
async fn rejects_invalid_token() {
let tokens: Arc<dyn WebhookTokenRepository> = InMemoryWebhookTokenRepository::new();
let watch_events = InMemoryWatchEventRepository::new();
let tokens = InMemoryStore::new();
let watch_events = Arc::clone(&tokens);
let event_publisher: Arc<dyn EventPublisher> = NoopEventPublisher::new();
let deps = IngestWatchEventDeps {
webhook_token: Arc::clone(&tokens),
webhook_token: Arc::clone(&tokens) as _,
watch_event_command: Arc::clone(&watch_events) as _,
watch_event_query: Arc::clone(&watch_events) as _,
event_publisher: Arc::clone(&event_publisher),

View File

@@ -2,7 +2,7 @@ use crate::test_support::generate_webhook_token_command;
use std::sync::Arc;
use domain::ports::WebhookTokenRepository;
use domain::testing::InMemoryWebhookTokenRepository;
use domain::testing::InMemoryStore;
use uuid::Uuid;
use crate::integrations::deps::{
@@ -15,7 +15,7 @@ use crate::integrations::{
#[tokio::test]
async fn revokes_existing_token() {
let tokens: Arc<dyn WebhookTokenRepository> = InMemoryWebhookTokenRepository::new();
let tokens: Arc<dyn WebhookTokenRepository> = InMemoryStore::new();
let user_id = Uuid::new_v4();

View File

@@ -5,10 +5,7 @@ use chrono::Utc;
use domain::{
models::MovieProfile,
ports::MovieCommand,
testing::{
FakeSearchCommand, InMemoryMovieProfileRepository, InMemoryMovieRepository,
PanicPersonCommand,
},
testing::{FakeSearchCommand, InMemoryStore, PanicPersonCommand},
value_objects::MovieId,
};
@@ -16,8 +13,8 @@ use crate::movies::{commands::EnrichMovieCommand, deps::EnrichMovieDeps, enrich_
#[tokio::test]
async fn stores_profile_and_indexes() {
let movie_repo = InMemoryMovieRepository::new();
let profile_repo = InMemoryMovieProfileRepository::new();
let movie_repo = InMemoryStore::new();
let profile_repo = Arc::clone(&movie_repo);
// PanicPersonCommand is safe here — empty cast/crew means upsert_batch is never called
let movie = test_movie_with_year("Test", 2024);
@@ -61,7 +58,7 @@ async fn stores_profile_and_indexes() {
.await
.unwrap();
assert_eq!(profile_repo.count(), 1);
assert_eq!(profile_repo.movie_profile_count(), 1);
}
struct NoopPersonCommand;
@@ -91,8 +88,8 @@ impl domain::ports::PersonCommand for NoopPersonCommand {
#[tokio::test]
async fn extracts_and_indexes_persons() {
let movie_repo = InMemoryMovieRepository::new();
let profile_repo = InMemoryMovieProfileRepository::new();
let movie_repo = InMemoryStore::new();
let profile_repo = Arc::clone(&movie_repo);
let movie = test_movie_with_year("Cast Movie", 2024);
let movie_id = MovieId::from_uuid(movie.id().value());
@@ -147,5 +144,5 @@ async fn extracts_and_indexes_persons() {
.await
.unwrap();
assert_eq!(profile_repo.count(), 1);
assert_eq!(profile_repo.movie_profile_count(), 1);
}

View File

@@ -4,7 +4,7 @@ use uuid::Uuid;
use domain::{
models::{CastMember, CrewMember, MovieProfile},
ports::MovieProfileRepository,
testing::InMemoryMovieProfileRepository,
testing::InMemoryStore,
value_objects::MovieId,
};
@@ -13,7 +13,7 @@ use crate::movies::get_movie_profile::{self, GetMovieProfileQuery};
#[tokio::test]
async fn returns_none_when_no_profile() {
let movie_profile = InMemoryMovieProfileRepository::new();
let movie_profile = InMemoryStore::new();
let deps = GetMovieProfileDeps { movie_profile };
let result = get_movie_profile::execute(
@@ -30,7 +30,7 @@ async fn returns_none_when_no_profile() {
#[tokio::test]
async fn returns_profile_with_cast_and_crew() {
let profile_repo = InMemoryMovieProfileRepository::new();
let profile_repo = InMemoryStore::new();
let movie_id = MovieId::generate();
let profile = MovieProfile {

View File

@@ -1,10 +1,10 @@
use domain::testing::InMemoryMovieRepository;
use domain::testing::InMemoryStore;
use crate::movies::{deps::GetMoviesDeps, get_movies, queries::GetMoviesQuery};
#[tokio::test]
async fn returns_empty_when_no_movies() {
let movie = InMemoryMovieRepository::new();
let movie = InMemoryStore::new();
let deps = GetMoviesDeps { movie };
let result = get_movies::execute(

View File

@@ -6,7 +6,7 @@ use domain::{
errors::DomainError,
models::MovieProfile,
ports::{MovieEnrichmentClient, MovieProfileRepository},
testing::{FakeMovieEnrichmentClient, InMemoryMovieProfileRepository},
testing::{FakeMovieEnrichmentClient, InMemoryStore},
value_objects::MovieId,
};
@@ -15,7 +15,7 @@ use crate::movies::request_enrichment;
#[tokio::test]
async fn returns_profile_when_none_cached() {
let enrichment = FakeMovieEnrichmentClient;
let profile_repo = InMemoryMovieProfileRepository::new();
let profile_repo = InMemoryStore::new();
let movie_id = MovieId::generate();
let result = request_enrichment::fetch_if_stale(
@@ -34,7 +34,7 @@ async fn returns_profile_when_none_cached() {
#[tokio::test]
async fn returns_none_when_profile_is_fresh() {
let enrichment = FakeMovieEnrichmentClient;
let profile_repo = InMemoryMovieProfileRepository::new();
let profile_repo = InMemoryStore::new();
let movie_id = MovieId::generate();
// Seed a fresh profile (enriched_at = now)
@@ -87,7 +87,7 @@ impl MovieEnrichmentClient for NotFoundEnrichmentClient {
#[tokio::test]
async fn returns_none_on_not_found_from_client() {
let enrichment = NotFoundEnrichmentClient;
let profile_repo = InMemoryMovieProfileRepository::new();
let profile_repo = InMemoryStore::new();
let movie_id = MovieId::generate();
let result = request_enrichment::fetch_if_stale(

View File

@@ -8,10 +8,7 @@ use domain::{
errors::DomainError,
models::Movie,
ports::{MetadataClient, MovieCommand, MovieQuery},
testing::{
FakeSearchCommand, InMemoryMovieProfileRepository, InMemoryMovieRepository,
NoopEventPublisher, NoopObjectStorage,
},
testing::{FakeSearchCommand, InMemoryStore, NoopEventPublisher, NoopObjectStorage},
value_objects::{ExternalMetadataId, PosterUrl},
};
@@ -19,9 +16,9 @@ use crate::movies::{deps::SyncPosterDeps, sync_poster};
fn default_deps() -> SyncPosterDeps {
SyncPosterDeps {
movie_command: InMemoryMovieRepository::new(),
movie_query: InMemoryMovieRepository::new(),
movie_profile: InMemoryMovieProfileRepository::new(),
movie_command: InMemoryStore::new(),
movie_query: InMemoryStore::new(),
movie_profile: InMemoryStore::new(),
metadata: Arc::new(domain::testing::FakeMetadataClient),
poster_fetcher: Arc::new(domain::testing::FakePosterFetcher),
object_storage: Arc::new(NoopObjectStorage),
@@ -41,7 +38,7 @@ async fn fails_when_movie_not_found() {
#[tokio::test]
async fn fails_when_no_external_id() {
let movies = InMemoryMovieRepository::new();
let movies = InMemoryStore::new();
let movie = test_movie_with_year("Test", 2024);
let movie_id = movie.id().value();
movies.upsert_movie(&movie).await.unwrap();
@@ -79,7 +76,7 @@ impl MetadataClient for FakeMetaWithPoster {
#[tokio::test]
async fn syncs_poster_for_movie_with_external_id() {
let movies = InMemoryMovieRepository::new();
let movies = InMemoryStore::new();
let ext_id = ExternalMetadataId::new("tmdb:999".into()).unwrap();
let movie = test_movie_with_external_id("Poster Movie", 2024, ext_id);
let movie_id = movie.id().value();

View File

@@ -2,7 +2,7 @@ use std::sync::Arc;
use domain::{
events::DomainEvent,
testing::{InMemorySocialRepository, NoopEventPublisher},
testing::{InMemoryStore, NoopEventPublisher},
value_objects::{FollowStatus, FollowTarget, SocialIdentity, UserId},
};
use uuid::Uuid;
@@ -14,11 +14,11 @@ use crate::social::{
};
fn make_cmd_deps() -> (
Arc<InMemorySocialRepository>,
Arc<InMemoryStore>,
Arc<NoopEventPublisher>,
SocialCommandDeps,
) {
let social = InMemorySocialRepository::new();
let social = InMemoryStore::new();
let events = NoopEventPublisher::new();
let deps = SocialCommandDeps {
social_command: Arc::clone(&social) as _,
@@ -359,7 +359,7 @@ async fn get_following_returns_accepted_targets() {
#[tokio::test]
async fn returns_accepted_followers() {
let social = InMemorySocialRepository::new();
let social = InMemoryStore::new();
let events = NoopEventPublisher::new();
let cmd_deps = SocialCommandDeps {
social_command: Arc::clone(&social) as _,
@@ -403,7 +403,7 @@ async fn returns_accepted_followers() {
#[tokio::test]
async fn returns_only_pending_followers() {
let social = InMemorySocialRepository::new();
let social = InMemoryStore::new();
let events = NoopEventPublisher::new();
let cmd_deps = SocialCommandDeps {
social_command: Arc::clone(&social) as _,

View File

@@ -7,7 +7,7 @@ use domain::{
ports::{
BlockQuery, FollowCommand, FollowGraphQuery, FollowQuery, SocialCommand, UserRepository,
},
testing::InMemoryUserRepository,
testing::InMemoryStore,
value_objects::{
FollowRelation, FollowStatus, FollowTarget, InstanceIdentity, SocialActor, SocialIdentity,
UserId,
@@ -19,7 +19,7 @@ use crate::social::local_service::LocalSocialService;
// ── Fakes ────────────────────────────────────────────────────────────────────
//
// No fake exists anywhere for FollowCommand/FollowQuery. `InMemorySocialRepository`
// No fake exists anywhere for FollowCommand/FollowQuery. `InMemoryStore`
// (domain::testing) implements SocialCommand/FollowGraphQuery/BlockQuery — the same
// level as LocalSocialService itself — so it cannot stand in as its dependency.
// A single struct backs both ports, mirroring how one database table serves both
@@ -246,7 +246,7 @@ fn instance() -> InstanceIdentity {
InstanceIdentity::new("http://md.example")
}
async fn register_user(repo: &Arc<InMemoryUserRepository>, username: &str) -> UserId {
async fn register_user(repo: &Arc<InMemoryStore>, username: &str) -> UserId {
let user = test_user(username);
let id = user.id().clone();
repo.save(&user).await.unwrap();
@@ -254,7 +254,7 @@ async fn register_user(repo: &Arc<InMemoryUserRepository>, username: &str) -> Us
}
fn service(
user_repo: Arc<InMemoryUserRepository>,
user_repo: Arc<InMemoryStore>,
follow_store: &Arc<FollowFakeStore>,
instance: InstanceIdentity,
) -> LocalSocialService {
@@ -270,7 +270,7 @@ fn service(
#[tokio::test]
async fn follow_local_user_writes_both_sides() {
let user_repo = InMemoryUserRepository::new();
let user_repo = InMemoryStore::new();
let bob_id = register_user(&user_repo, "bob").await;
let alice_id = register_user(&user_repo, "alice").await;
let follow_store = FollowFakeStore::new();
@@ -302,7 +302,7 @@ async fn follow_local_user_writes_both_sides() {
#[tokio::test]
async fn follow_self_is_rejected() {
let user_repo = InMemoryUserRepository::new();
let user_repo = InMemoryStore::new();
let alice_id = register_user(&user_repo, "alice").await;
let follow_store = FollowFakeStore::new();
let svc = service(user_repo, &follow_store, instance());
@@ -335,7 +335,7 @@ async fn follow_self_is_rejected() {
#[tokio::test]
async fn follow_remote_target_errors_rather_than_silently_succeeding() {
let user_repo = InMemoryUserRepository::new();
let user_repo = InMemoryStore::new();
let alice_id = register_user(&user_repo, "alice").await;
let follow_store = FollowFakeStore::new();
let svc = service(user_repo, &follow_store, instance());
@@ -376,7 +376,7 @@ async fn reject_follow_updates_follower_status_but_removes_the_follow_row() {
// the follow row outright. A test that only checked the follower row would
// pass against a reject_follow "corrected" into accept_follow's symmetry —
// the second assertion is the one that carries the weight.
let user_repo = InMemoryUserRepository::new();
let user_repo = InMemoryStore::new();
let owner_id = register_user(&user_repo, "owner").await;
let requester_id = register_user(&user_repo, "requester").await;
let follow_store = FollowFakeStore::new();
@@ -422,7 +422,7 @@ async fn reject_follow_updates_follower_status_but_removes_the_follow_row() {
#[tokio::test]
async fn block_errors_and_get_blocked_is_empty() {
let user_repo = InMemoryUserRepository::new();
let user_repo = InMemoryStore::new();
let alice_id = register_user(&user_repo, "alice").await;
let follow_store = FollowFakeStore::new();
let svc = service(user_repo, &follow_store, instance());

View File

@@ -1,8 +1,7 @@
use std::sync::Arc;
use domain::testing::{
InMemoryGoalRepository, InMemorySocialRepository, InMemoryWrapUpRepository,
InMemoryWrapUpStatsQuery, NoopFederationAdminQuery,
InMemoryStore, InMemoryWrapUpRepository, InMemoryWrapUpStatsQuery, NoopFederationAdminQuery,
};
use domain::{
ports::{
@@ -17,11 +16,7 @@ use domain::{
testing::{
FakeAuthService, FakeDiaryQuery, FakeDocumentParser, FakeMetadataClient,
FakePasswordHasher, FakePersonQuery, FakePosterFetcher, FakeSearchCommand, FakeSearchPort,
FakeStatsRepository, InMemoryImportProfileRepository, InMemoryImportSessionRepository,
InMemoryMovieProfileRepository, InMemoryMovieRepository, InMemoryProfileFieldsRepo,
InMemoryRefreshSessionRepository, InMemoryReviewRepository, InMemoryUserRepository,
InMemoryUserSettingsRepository, InMemoryWatchEventRepository, InMemoryWatchlistRepository,
InMemoryWebhookTokenRepository, NoopEventPublisher, NoopObjectStorage, PanicDiaryExporter,
FakeStatsRepository, NoopEventPublisher, NoopObjectStorage, PanicDiaryExporter,
PanicPersonCommand,
},
};
@@ -89,14 +84,11 @@ impl Default for TestContextBuilder {
impl TestContextBuilder {
pub fn new() -> Self {
let movies = InMemoryMovieRepository::new();
let watch_events = InMemoryWatchEventRepository::new();
let goals = InMemoryGoalRepository::new();
let social = InMemorySocialRepository::new();
let store = InMemoryStore::new();
Self {
movie_command: Arc::clone(&movies) as _,
movie_query: movies as _,
review_repo: InMemoryReviewRepository::new(),
movie_command: Arc::clone(&store) as _,
movie_query: Arc::clone(&store) as _,
review_repo: Arc::clone(&store) as _,
diary_repo: FakeDiaryQuery::new(),
diary_exporter: Arc::new(PanicDiaryExporter),
document_parser: Arc::new(FakeDocumentParser),
@@ -107,30 +99,30 @@ impl TestContextBuilder {
event_publisher: NoopEventPublisher::new(),
auth_service: Arc::new(FakeAuthService),
password_hasher: Arc::new(FakePasswordHasher),
user_repo: InMemoryUserRepository::new(),
import_session_repo: InMemoryImportSessionRepository::new(),
import_profile_repo: InMemoryImportProfileRepository::new(),
movie_profile_repo: InMemoryMovieProfileRepository::new(),
watchlist_repo: InMemoryWatchlistRepository::new(),
watch_event_command: Arc::clone(&watch_events) as _,
watch_event_query: watch_events as _,
webhook_token_repo: InMemoryWebhookTokenRepository::new(),
profile_fields_repo: InMemoryProfileFieldsRepo::new(),
user_repo: Arc::clone(&store) as _,
import_session_repo: Arc::clone(&store) as _,
import_profile_repo: Arc::clone(&store) as _,
movie_profile_repo: Arc::clone(&store) as _,
watchlist_repo: Arc::clone(&store) as _,
watch_event_command: Arc::clone(&store) as _,
watch_event_query: Arc::clone(&store) as _,
webhook_token_repo: Arc::clone(&store) as _,
profile_fields_repo: Arc::clone(&store) as _,
person_command: Arc::new(PanicPersonCommand),
person_query: Arc::new(FakePersonQuery),
search_port: Arc::new(FakeSearchPort),
search_command: Arc::new(FakeSearchCommand),
wrapup_stats: InMemoryWrapUpStatsQuery::new(),
wrapup_repo: InMemoryWrapUpRepository::new(),
goal_command: Arc::clone(&goals) as _,
goal_query: goals as _,
user_settings_repo: InMemoryUserSettingsRepository::new(),
goal_command: Arc::clone(&store) as _,
goal_query: Arc::clone(&store) as _,
user_settings_repo: Arc::clone(&store) as _,
review_logger: Arc::new(NoopReviewLogger),
social_command: Arc::clone(&social) as _,
social_query_unified: Arc::clone(&social) as _,
block_query: Arc::clone(&social) as _,
social_command: Arc::clone(&store) as _,
social_query_unified: Arc::clone(&store) as _,
block_query: Arc::clone(&store) as _,
federation_admin: Arc::new(NoopFederationAdminQuery),
refresh_session_repo: InMemoryRefreshSessionRepository::new(),
refresh_session_repo: Arc::clone(&store) as _,
config: AppConfig {
allow_registration: true,
base_url: "http://localhost:3000".into(),

View File

@@ -2,7 +2,7 @@ use crate::test_support::register_command;
use std::sync::Arc;
use domain::models::UserRole;
use domain::testing::InMemoryUserRepository;
use domain::testing::InMemoryStore;
use crate::{
auth::{commands::RegisterCommand, deps::RegisterDeps, register},
@@ -40,7 +40,7 @@ async fn register_user(
#[tokio::test]
async fn authorize_admin_is_true_for_an_admin_user() {
let users = InMemoryUserRepository::new();
let users = InMemoryStore::new();
let b = TestContextBuilder::new().with_users(Arc::clone(&users) as _);
let user = register_user(&b, "admin@example.com", "admin_user", UserRole::Admin).await;
@@ -56,7 +56,7 @@ async fn authorize_admin_is_true_for_an_admin_user() {
#[tokio::test]
async fn authorize_admin_is_false_for_a_regular_user() {
let users = InMemoryUserRepository::new();
let users = InMemoryStore::new();
let b = TestContextBuilder::new().with_users(Arc::clone(&users) as _);
let user = register_user(
&b,

View File

@@ -3,7 +3,7 @@ use std::sync::Arc;
use domain::models::{ProfileField, User, UserProfile, UserRole};
use domain::ports::UserRepository;
use domain::testing::InMemoryUserRepository;
use domain::testing::InMemoryStore;
use domain::value_objects::{Email, PasswordHash, UserId, Username};
use uuid::Uuid;
@@ -15,7 +15,7 @@ use crate::{
#[tokio::test]
async fn returns_profile_for_existing_user() {
let users = InMemoryUserRepository::new();
let users = InMemoryStore::new();
let b = TestContextBuilder::new().with_users(Arc::clone(&users) as _);
let user_repo = b.user_repo.clone();
let reg_deps = RegisterDeps {
@@ -66,7 +66,7 @@ async fn fails_for_nonexistent_user() {
#[tokio::test]
async fn returns_profile_with_avatar_banner_and_fields() {
let users = InMemoryUserRepository::new();
let users = InMemoryStore::new();
let uid = UserId::generate();
let user = User::from_persistence(
@@ -87,7 +87,7 @@ async fn returns_profile_with_avatar_banner_and_fields() {
}],
},
);
users.store.lock().unwrap().insert(uid.value(), user);
users.seed_user(user);
let b = TestContextBuilder::new().with_users(Arc::clone(&users) as _);
let user_repo = b.user_repo.clone();

View File

@@ -3,7 +3,7 @@ use std::sync::Arc;
use domain::events::DomainEvent;
use domain::ports::UserRepository;
use domain::testing::{InMemoryUserRepository, NoopEventPublisher};
use domain::testing::{InMemoryStore, NoopEventPublisher};
use uuid::Uuid;
use crate::{
@@ -12,7 +12,7 @@ use crate::{
users::{commands::UpdateProfileCommand, deps::UpdateProfileDeps, update_profile},
};
async fn register_user(b: &TestContextBuilder, users: &Arc<InMemoryUserRepository>) -> Uuid {
async fn register_user(b: &TestContextBuilder, users: &Arc<InMemoryStore>) -> Uuid {
let reg_deps = RegisterDeps {
user: b.user_repo.clone(),
password_hasher: b.password_hasher.clone(),
@@ -32,7 +32,7 @@ async fn register_user(b: &TestContextBuilder, users: &Arc<InMemoryUserRepositor
#[tokio::test]
async fn updates_display_name() {
let users = InMemoryUserRepository::new();
let users = InMemoryStore::new();
let events = NoopEventPublisher::new();
let b = TestContextBuilder::new()
.with_users(Arc::clone(&users) as _)
@@ -64,7 +64,7 @@ async fn updates_display_name() {
#[tokio::test]
async fn rejects_invalid_avatar_content_type() {
let users = InMemoryUserRepository::new();
let users = InMemoryStore::new();
let b = TestContextBuilder::new().with_users(Arc::clone(&users) as _);
let deps = UpdateProfileDeps {
user: b.user_repo.clone(),
@@ -88,7 +88,7 @@ async fn rejects_invalid_avatar_content_type() {
#[tokio::test]
async fn uploads_avatar() {
let users = InMemoryUserRepository::new();
let users = InMemoryStore::new();
let events = NoopEventPublisher::new();
let b = TestContextBuilder::new()
.with_users(Arc::clone(&users) as _)
@@ -126,7 +126,7 @@ async fn uploads_avatar() {
#[tokio::test]
async fn uploads_banner() {
let users = InMemoryUserRepository::new();
let users = InMemoryStore::new();
let events = NoopEventPublisher::new();
let b = TestContextBuilder::new()
.with_users(Arc::clone(&users) as _)
@@ -185,7 +185,7 @@ async fn fails_for_nonexistent_user() {
#[tokio::test]
async fn rejects_invalid_banner_content_type() {
let users = InMemoryUserRepository::new();
let users = InMemoryStore::new();
let b = TestContextBuilder::new().with_users(Arc::clone(&users) as _);
let deps = UpdateProfileDeps {
user: b.user_repo.clone(),
@@ -209,7 +209,7 @@ async fn rejects_invalid_banner_content_type() {
#[tokio::test]
async fn text_only_update_emits_user_updated_no_image_stored() {
let users = InMemoryUserRepository::new();
let users = InMemoryStore::new();
let events = NoopEventPublisher::new();
let b = TestContextBuilder::new()
.with_users(Arc::clone(&users) as _)

View File

@@ -2,7 +2,7 @@ use std::sync::Arc;
use domain::events::DomainEvent;
use domain::models::ProfileField;
use domain::testing::{InMemoryProfileFieldsRepo, NoopEventPublisher};
use domain::testing::{InMemoryStore, NoopEventPublisher};
use uuid::Uuid;
use crate::{
@@ -14,7 +14,7 @@ use crate::{
#[tokio::test]
async fn saves_profile_fields() {
let fields_repo = InMemoryProfileFieldsRepo::new();
let fields_repo = InMemoryStore::new();
let events = NoopEventPublisher::new();
let b = TestContextBuilder::new()
.with_profile_fields(Arc::clone(&fields_repo) as _)

View File

@@ -1,7 +1,7 @@
use crate::test_support::update_user_settings_command;
use std::sync::Arc;
use domain::testing::InMemoryUserSettingsRepository;
use domain::testing::InMemoryStore;
use uuid::Uuid;
use crate::{
@@ -15,7 +15,7 @@ use crate::{
#[tokio::test]
async fn updates_federate_goals() {
let settings_repo = InMemoryUserSettingsRepository::new();
let settings_repo = InMemoryStore::new();
let b = TestContextBuilder::new().with_user_settings(Arc::clone(&settings_repo) as _);
let user_settings = b.user_settings_repo.clone();
let uid = Uuid::nil();
@@ -42,7 +42,7 @@ async fn updates_federate_goals() {
#[tokio::test]
async fn updates_federate_reviews() {
let settings_repo = InMemoryUserSettingsRepository::new();
let settings_repo = InMemoryStore::new();
let b = TestContextBuilder::new().with_user_settings(Arc::clone(&settings_repo) as _);
let user_settings = b.user_settings_repo.clone();
let uid = Uuid::nil();
@@ -69,7 +69,7 @@ async fn updates_federate_reviews() {
#[tokio::test]
async fn updates_federate_watchlist() {
let settings_repo = InMemoryUserSettingsRepository::new();
let settings_repo = InMemoryStore::new();
let b = TestContextBuilder::new().with_user_settings(Arc::clone(&settings_repo) as _);
let user_settings = b.user_settings_repo.clone();
let uid = Uuid::nil();

View File

@@ -4,15 +4,12 @@ use std::sync::Arc;
use domain::{
ports::MovieCommand,
testing::{InMemoryMovieRepository, InMemoryWatchlistRepository, NoopEventPublisher},
testing::{InMemoryStore, NoopEventPublisher},
};
use crate::watchlist::{add, commands::AddToWatchlistCommand, deps::WatchlistAddDeps};
fn make_deps(
movies: Arc<InMemoryMovieRepository>,
watchlist: Arc<InMemoryWatchlistRepository>,
) -> WatchlistAddDeps {
fn make_deps(movies: Arc<InMemoryStore>, watchlist: Arc<InMemoryStore>) -> WatchlistAddDeps {
WatchlistAddDeps {
movie_command: Arc::clone(&movies) as _,
movie_query: movies,
@@ -24,8 +21,8 @@ fn make_deps(
#[tokio::test]
async fn test_add_to_watchlist_resolves_and_saves() {
let movies = InMemoryMovieRepository::new();
let watchlist = InMemoryWatchlistRepository::new();
let movies = InMemoryStore::new();
let watchlist = Arc::clone(&movies);
let movie = test_movie_with_year("The Thing", 1982);
let movie_uuid = movie.id().value();
@@ -37,13 +34,13 @@ async fn test_add_to_watchlist_resolves_and_saves() {
add::execute(&deps, cmd).await.unwrap();
assert_eq!(watchlist.count(), 1);
assert_eq!(watchlist.watchlist_count(), 1);
}
#[tokio::test]
async fn test_add_to_watchlist_already_present_is_idempotent() {
let movies = InMemoryMovieRepository::new();
let watchlist = InMemoryWatchlistRepository::new();
let movies = InMemoryStore::new();
let watchlist = Arc::clone(&movies);
let movie = test_movie_with_year("RoboCop", 1987);
let movie_uuid = movie.id().value();
@@ -57,13 +54,17 @@ async fn test_add_to_watchlist_already_present_is_idempotent() {
add::execute(&deps, make_cmd()).await.unwrap();
add::execute(&deps, make_cmd()).await.unwrap();
assert_eq!(watchlist.count(), 1, "idempotent add should not duplicate");
assert_eq!(
watchlist.watchlist_count(),
1,
"idempotent add should not duplicate"
);
}
#[tokio::test]
async fn test_add_to_watchlist_with_manual_movie() {
let movies = InMemoryMovieRepository::new();
let watchlist = InMemoryWatchlistRepository::new();
let movies = InMemoryStore::new();
let watchlist = Arc::clone(&movies);
let deps = make_deps(Arc::clone(&movies), Arc::clone(&watchlist));
@@ -74,14 +75,14 @@ async fn test_add_to_watchlist_with_manual_movie() {
add::execute(&deps, cmd).await.unwrap();
assert_eq!(watchlist.count(), 1);
assert_eq!(movies.count(), 1);
assert_eq!(watchlist.watchlist_count(), 1);
assert_eq!(movies.movie_count(), 1);
}
#[tokio::test]
async fn test_add_to_watchlist_movie_not_found_by_id() {
let movies = InMemoryMovieRepository::new();
let watchlist = InMemoryWatchlistRepository::new();
let movies = InMemoryStore::new();
let watchlist = Arc::clone(&movies);
let deps = make_deps(Arc::clone(&movies), Arc::clone(&watchlist));

View File

@@ -3,10 +3,7 @@ use std::sync::Arc;
use uuid::Uuid;
use domain::testing::{
InMemoryRemoteWatchlistRepository, InMemoryUserRepository, InMemoryWatchlistRepository,
PanicRemoteWatchlistRepository, PanicWatchlistRepository,
};
use domain::testing::{InMemoryStore, PanicRemoteWatchlistRepository, PanicWatchlistRepository};
use domain::value_objects::Email;
use crate::auth::deps::RegisterDeps;
@@ -37,7 +34,7 @@ async fn watchlist_for_owner_returns_local_when_user_row_exists() {
let deps = GetWatchlistForOwnerDeps {
user: b.user_repo.clone(),
watchlist: InMemoryWatchlistRepository::new(),
watchlist: InMemoryStore::new(),
remote_watchlist: Arc::new(PanicRemoteWatchlistRepository),
};
@@ -52,20 +49,18 @@ async fn watchlist_for_owner_returns_local_when_user_row_exists() {
async fn watchlist_for_owner_returns_remote_when_no_local_row() {
let owner_id = Uuid::new_v4();
let remote = InMemoryRemoteWatchlistRepository::with_entries(vec![
domain::models::RemoteWatchlistEntry {
ap_id: "https://remote.example/ap/1".into(),
actor_url: "https://remote.example/users/owner".into(),
movie_title: "Remote Movie".into(),
release_year: 2021,
external_metadata_id: None,
poster_url: None,
added_at: chrono::Utc::now(),
},
]);
let remote = InMemoryStore::with_remote_watchlist(vec![domain::models::RemoteWatchlistEntry {
ap_id: "https://remote.example/ap/1".into(),
actor_url: "https://remote.example/users/owner".into(),
movie_title: "Remote Movie".into(),
release_year: 2021,
external_metadata_id: None,
poster_url: None,
added_at: chrono::Utc::now(),
}]);
let deps = GetWatchlistForOwnerDeps {
user: InMemoryUserRepository::new(),
user: InMemoryStore::new(),
watchlist: Arc::new(PanicWatchlistRepository),
remote_watchlist: remote,
};
@@ -94,7 +89,7 @@ async fn watchlist_for_owner_local_arm_validates_limit() {
let deps = GetWatchlistForOwnerDeps {
user: b.user_repo.clone(),
watchlist: InMemoryWatchlistRepository::new(),
watchlist: InMemoryStore::new(),
remote_watchlist: Arc::new(PanicRemoteWatchlistRepository),
};
@@ -111,10 +106,10 @@ async fn watchlist_for_owner_local_arm_validates_limit() {
#[tokio::test]
async fn watchlist_for_owner_remote_arm_ignores_invalid_limit() {
let owner_id = Uuid::new_v4();
let remote = InMemoryRemoteWatchlistRepository::new();
let remote = InMemoryStore::new();
let deps = GetWatchlistForOwnerDeps {
user: InMemoryUserRepository::new(),
user: InMemoryStore::new(),
watchlist: Arc::new(PanicWatchlistRepository),
remote_watchlist: remote,
};

View File

@@ -2,7 +2,7 @@ use std::sync::Arc;
use domain::models::WatchlistEntry;
use domain::ports::WatchlistRepository;
use domain::testing::InMemoryWatchlistRepository;
use domain::testing::InMemoryStore;
use domain::value_objects::{MovieId, UserId};
use uuid::Uuid;
@@ -11,7 +11,7 @@ use crate::watchlist::{deps::IsOnWatchlistDeps, is_on, queries::IsOnWatchlistQue
#[tokio::test]
async fn returns_true_when_present() {
let watchlist = InMemoryWatchlistRepository::new();
let watchlist = InMemoryStore::new();
let uid = Uuid::new_v4();
let mid = Uuid::new_v4();
watchlist

View File

@@ -3,7 +3,7 @@ use std::sync::Arc;
use domain::events::DomainEvent;
use domain::models::WatchlistEntry;
use domain::ports::WatchlistRepository;
use domain::testing::{InMemoryWatchlistRepository, NoopEventPublisher};
use domain::testing::{InMemoryStore, NoopEventPublisher};
use domain::value_objects::{MovieId, UserId};
use uuid::Uuid;
@@ -14,7 +14,7 @@ use crate::watchlist::{
#[tokio::test]
async fn removes_entry_and_emits_event() {
let watchlist = InMemoryWatchlistRepository::new();
let watchlist = InMemoryStore::new();
let events = NoopEventPublisher::new();
let uid = Uuid::new_v4();
let mid = Uuid::new_v4();
@@ -40,7 +40,7 @@ async fn removes_entry_and_emits_event() {
.await
.unwrap();
assert_eq!(watchlist.count(), 0);
assert_eq!(watchlist.watchlist_count(), 0);
let published = events.published();
assert!(
published