Files
thoughts/crates/adapters/postgres/src/follow/tests.rs

142 lines
4.5 KiB
Rust

use super::*;
use crate::test_helpers::seed_user;
use chrono::Utc;
use domain::value_objects::*;
#[sqlx::test(migrations = "./migrations")]
async fn save_and_find_follow(pool: sqlx::PgPool) {
let alice = seed_user(&pool, "alice", "alice@ex.com").await;
let bob = seed_user(&pool, "bob", "bob@ex.com").await;
let repo = PgFollowRepository::new(pool);
let follow = Follow {
follower_id: alice.id.clone(),
following_id: bob.id.clone(),
state: FollowState::Accepted,
ap_id: None,
created_at: Utc::now(),
};
repo.save(&follow).await.unwrap();
let found = repo.find(&alice.id, &bob.id).await.unwrap().unwrap();
assert_eq!(found.state, FollowState::Accepted);
}
#[sqlx::test(migrations = "./migrations")]
async fn update_state(pool: sqlx::PgPool) {
let alice = seed_user(&pool, "alice", "alice@ex.com").await;
let bob = seed_user(&pool, "bob", "bob@ex.com").await;
let repo = PgFollowRepository::new(pool);
let follow = Follow {
follower_id: alice.id.clone(),
following_id: bob.id.clone(),
state: FollowState::Pending,
ap_id: None,
created_at: Utc::now(),
};
repo.save(&follow).await.unwrap();
repo.update_state(&alice.id, &bob.id, &FollowState::Accepted)
.await
.unwrap();
let found = repo.find(&alice.id, &bob.id).await.unwrap().unwrap();
assert_eq!(found.state, FollowState::Accepted);
}
#[sqlx::test(migrations = "./migrations")]
async fn get_accepted_following_ids(pool: sqlx::PgPool) {
let alice = seed_user(&pool, "alice", "alice@ex.com").await;
let bob = seed_user(&pool, "bob", "bob@ex.com").await;
let repo = PgFollowRepository::new(pool);
let follow = Follow {
follower_id: alice.id.clone(),
following_id: bob.id.clone(),
state: FollowState::Accepted,
ap_id: None,
created_at: Utc::now(),
};
repo.save(&follow).await.unwrap();
let ids = repo.get_accepted_following_ids(&alice.id).await.unwrap();
assert_eq!(ids, vec![bob.id]);
}
#[sqlx::test(migrations = "./migrations")]
async fn list_mutual_returns_only_mutual_accepted_follows(pool: sqlx::PgPool) {
let alice = seed_user(&pool, "alice", "alice@ex.com").await;
let bob = seed_user(&pool, "bob", "bob@ex.com").await;
let carol = seed_user(&pool, "carol", "carol@ex.com").await;
let repo = PgFollowRepository::new(pool);
let page = domain::models::feed::PageParams {
page: 1,
per_page: 20,
};
// alice → bob (accepted), bob → alice (accepted) = friends
repo.save(&Follow {
follower_id: alice.id.clone(),
following_id: bob.id.clone(),
state: FollowState::Accepted,
ap_id: None,
created_at: Utc::now(),
})
.await
.unwrap();
repo.save(&Follow {
follower_id: bob.id.clone(),
following_id: alice.id.clone(),
state: FollowState::Accepted,
ap_id: None,
created_at: Utc::now(),
})
.await
.unwrap();
// alice → carol (accepted), carol does NOT follow back = not a friend
repo.save(&Follow {
follower_id: alice.id.clone(),
following_id: carol.id.clone(),
state: FollowState::Accepted,
ap_id: None,
created_at: Utc::now(),
})
.await
.unwrap();
let result = repo.list_mutual(&alice.id, &page).await.unwrap();
assert_eq!(result.total, 1);
assert_eq!(result.items.len(), 1);
assert_eq!(result.items[0].id, bob.id);
}
#[sqlx::test(migrations = "./migrations")]
async fn list_mutual_excludes_pending_follows(pool: sqlx::PgPool) {
let alice = seed_user(&pool, "alice", "alice@ex.com").await;
let bob = seed_user(&pool, "bob", "bob@ex.com").await;
let repo = PgFollowRepository::new(pool);
let page = domain::models::feed::PageParams {
page: 1,
per_page: 20,
};
// alice → bob (accepted), bob → alice (PENDING) = NOT a friend
repo.save(&Follow {
follower_id: alice.id.clone(),
following_id: bob.id.clone(),
state: FollowState::Accepted,
ap_id: None,
created_at: Utc::now(),
})
.await
.unwrap();
repo.save(&Follow {
follower_id: bob.id.clone(),
following_id: alice.id.clone(),
state: FollowState::Pending,
ap_id: None,
created_at: Utc::now(),
})
.await
.unwrap();
let result = repo.list_mutual(&alice.id, &page).await.unwrap();
assert_eq!(result.total, 0);
assert!(result.items.is_empty());
}