diff --git a/crates/buzz-db/src/channel.rs b/crates/buzz-db/src/channel.rs index a9cecc1410..e2c7eb64ca 100644 --- a/crates/buzz-db/src/channel.rs +++ b/crates/buzz-db/src/channel.rs @@ -1235,6 +1235,67 @@ mod tests { Keys::generate().public_key().to_bytes().to_vec() } + async fn make_test_community(pool: &PgPool) -> Uuid { + let id = Uuid::new_v4(); + let host = format!("channel-test-{}.example", id.simple()); + sqlx::query("INSERT INTO communities (id, host) VALUES ($1, $2)") + .bind(id) + .bind(host) + .execute(pool) + .await + .expect("insert test community"); + id + } + + async fn create_test_channel( + pool: &PgPool, + name: &str, + channel_type: ChannelType, + visibility: ChannelVisibility, + description: Option<&str>, + created_by: &[u8], + ttl_seconds: Option, + ) -> Result { + let id = Uuid::new_v4(); + let community_id = make_test_community(pool).await; + + sqlx::query( + r#" + INSERT INTO channels + (id, community_id, name, channel_type, visibility, description, created_by, ttl_seconds, ttl_deadline) + VALUES + ($1, $2, $3, $4::channel_type, $5::channel_visibility, $6, $7, $8, + CASE WHEN $8 IS NOT NULL THEN NOW() + ($8 || ' seconds')::interval ELSE NULL END) + "#, + ) + .bind(id) + .bind(community_id) + .bind(name) + .bind(channel_type.as_str()) + .bind(visibility.as_str()) + .bind(description) + .bind(created_by) + .bind(ttl_seconds) + .execute(pool) + .await + .expect("insert test channel"); + + sqlx::query( + r#" + INSERT INTO channel_members (channel_id, pubkey, role, invited_by) + VALUES ($1, $2, 'owner', $3) + "#, + ) + .bind(id) + .bind(created_by) + .bind(created_by) + .execute(pool) + .await + .expect("insert owner membership"); + + get_channel(pool, id).await + } + /// Agent owner (non-admin) can remove their own bot from a channel. #[tokio::test] #[ignore = "requires Postgres"] @@ -1255,7 +1316,7 @@ mod tests { ensure_user(&pool, &channel_owner_pk) .await .expect("ensure channel owner"); - let channel = create_channel( + let channel = create_test_channel( &pool, "test-bot-remove", ChannelType::Stream, @@ -1298,7 +1359,7 @@ mod tests { let owner_pk = random_pubkey(); ensure_user(&pool, &owner_pk).await.expect("ensure owner"); - let channel = create_channel( + let channel = create_test_channel( &pool, "test-unarchive-renews-ttl", ChannelType::Stream, @@ -1365,7 +1426,7 @@ mod tests { ensure_user(&pool, &channel_owner_pk) .await .expect("ensure channel owner"); - let channel = create_channel( + let channel = create_test_channel( &pool, "test-bot-no-remove", ChannelType::Stream, diff --git a/crates/buzz-db/src/thread.rs b/crates/buzz-db/src/thread.rs index 4ccd8a2483..0fd3ac6d68 100644 --- a/crates/buzz-db/src/thread.rs +++ b/crates/buzz-db/src/thread.rs @@ -659,7 +659,7 @@ pub async fn get_thread_metadata_by_event( mod tests { use super::*; use crate::{ - channel::{create_channel, ChannelType, ChannelVisibility}, + channel::{ChannelType, ChannelVisibility}, event::{insert_event_with_thread_metadata, ThreadMetadataParams}, }; use nostr::{EventBuilder, Keys, Kind}; @@ -687,12 +687,73 @@ mod tests { .expect("event timestamp is valid") } + async fn make_test_community(pool: &PgPool) -> Uuid { + let id = Uuid::new_v4(); + let host = format!("thread-test-{}.example", id.simple()); + sqlx::query("INSERT INTO communities (id, host) VALUES ($1, $2)") + .bind(id) + .bind(host) + .execute(pool) + .await + .expect("insert test community"); + id + } + + async fn create_test_channel( + pool: &PgPool, + name: &str, + channel_type: ChannelType, + visibility: ChannelVisibility, + description: Option<&str>, + created_by: &[u8], + ttl_seconds: Option, + ) -> crate::error::Result { + let id = Uuid::new_v4(); + let community_id = make_test_community(pool).await; + + sqlx::query( + r#" + INSERT INTO channels + (id, community_id, name, channel_type, visibility, description, created_by, ttl_seconds, ttl_deadline) + VALUES + ($1, $2, $3, $4::channel_type, $5::channel_visibility, $6, $7, $8, + CASE WHEN $8 IS NOT NULL THEN NOW() + ($8 || ' seconds')::interval ELSE NULL END) + "#, + ) + .bind(id) + .bind(community_id) + .bind(name) + .bind(channel_type.as_str()) + .bind(visibility.as_str()) + .bind(description) + .bind(created_by) + .bind(ttl_seconds) + .execute(pool) + .await + .expect("insert test channel"); + + sqlx::query( + r#" + INSERT INTO channel_members (channel_id, pubkey, role, invited_by) + VALUES ($1, $2, 'owner', $3) + "#, + ) + .bind(id) + .bind(created_by) + .bind(created_by) + .execute(pool) + .await + .expect("insert owner membership"); + + crate::channel::get_channel(pool, id).await + } + #[tokio::test] #[ignore = "requires Postgres"] async fn get_thread_replies_reconstructs_stored_events() { let pool = setup_pool().await; let author = Keys::generate(); - let channel = create_channel( + let channel = create_test_channel( &pool, &format!("thread-replies-{}", Uuid::new_v4()), ChannelType::Stream, @@ -752,7 +813,7 @@ mod tests { async fn get_thread_replies_skips_unreconstructable_row() { let pool = setup_pool().await; let author = Keys::generate(); - let channel = create_channel( + let channel = create_test_channel( &pool, &format!("thread-replies-corrupt-{}", Uuid::new_v4()), ChannelType::Stream,