relay filter/appview bootstrap
at main 12 kB view raw
1mod common; 2 3use chrono::Utc; 4use reqwest::StatusCode; 5use serde_json::{json, Value}; 6use prism::records::{ 7 NewAccount, NewRecord, CHANNEL_COLLECTION, INVITE_COLLECTION, LATTICE_COLLECTION, 8 MEMBERSHIP_COLLECTION, SHARD_COLLECTION, 9}; 10 11async fn insert_test_account(pool: &sqlx::PgPool, did: &str) { 12 prism::db::upsert_account( 13 pool, 14 &NewAccount { 15 did: did.to_string(), 16 handle: did.to_string(), 17 created_at: Utc::now(), 18 }, 19 ) 20 .await 21 .unwrap(); 22} 23 24async fn insert_test_channel(pool: &sqlx::PgPool, cid: &str, creator_did: &str, name: &str) { 25 let uri = format!("at://{}/systems.gmstn.development.channel/{}", creator_did, cid); 26 let now = Utc::now(); 27 prism::db::insert_record( 28 pool, 29 &NewRecord { 30 uri, 31 cid: cid.to_string(), 32 collection: CHANNEL_COLLECTION.to_string(), 33 creator_did: creator_did.to_string(), 34 created_at: now, 35 indexed_at: now, 36 data: json!({"name": name, "topic": "test topic"}), 37 target_did: None, 38 ref_cids: vec![], 39 }, 40 ) 41 .await 42 .unwrap(); 43} 44 45async fn insert_test_invite( 46 pool: &sqlx::PgPool, 47 cid: &str, 48 creator_did: &str, 49 channel_cid: &str, 50 recipient_did: &str, 51) { 52 let uri = format!( 53 "at://{}/systems.gmstn.development.channel.invite/{}", 54 creator_did, cid 55 ); 56 let now = Utc::now(); 57 prism::db::insert_record( 58 pool, 59 &NewRecord { 60 uri, 61 cid: cid.to_string(), 62 collection: INVITE_COLLECTION.to_string(), 63 creator_did: creator_did.to_string(), 64 created_at: now, 65 indexed_at: now, 66 data: json!({"recipient": recipient_did}), 67 target_did: Some(recipient_did.to_string()), 68 ref_cids: vec![channel_cid.to_string()], 69 }, 70 ) 71 .await 72 .unwrap(); 73} 74 75async fn insert_test_membership( 76 pool: &sqlx::PgPool, 77 cid: &str, 78 recipient_did: &str, 79 channel_cid: &str, 80 invite_cid: &str, 81) { 82 let uri = format!( 83 "at://{}/systems.gmstn.development.channel.membership/{}", 84 recipient_did, cid 85 ); 86 let now = Utc::now(); 87 prism::db::insert_record( 88 pool, 89 &NewRecord { 90 uri, 91 cid: cid.to_string(), 92 collection: MEMBERSHIP_COLLECTION.to_string(), 93 creator_did: recipient_did.to_string(), 94 created_at: now, 95 indexed_at: now, 96 data: json!({"state": "accepted"}), 97 target_did: Some(recipient_did.to_string()), 98 ref_cids: vec![channel_cid.to_string(), invite_cid.to_string()], 99 }, 100 ) 101 .await 102 .unwrap(); 103} 104 105async fn insert_test_lattice(pool: &sqlx::PgPool, cid: &str, creator_did: &str) { 106 let uri = format!("at://{}/systems.gmstn.development.lattice/{}", creator_did, cid); 107 let now = Utc::now(); 108 prism::db::insert_record( 109 pool, 110 &NewRecord { 111 uri, 112 cid: cid.to_string(), 113 collection: LATTICE_COLLECTION.to_string(), 114 creator_did: creator_did.to_string(), 115 created_at: now, 116 indexed_at: now, 117 data: json!({"description": "test lattice"}), 118 target_did: None, 119 ref_cids: vec![], 120 }, 121 ) 122 .await 123 .unwrap(); 124} 125 126async fn insert_test_shard(pool: &sqlx::PgPool, cid: &str, creator_did: &str) { 127 let uri = format!("at://{}/systems.gmstn.development.shard/{}", creator_did, cid); 128 let now = Utc::now(); 129 prism::db::insert_record( 130 pool, 131 &NewRecord { 132 uri, 133 cid: cid.to_string(), 134 collection: SHARD_COLLECTION.to_string(), 135 creator_did: creator_did.to_string(), 136 created_at: now, 137 indexed_at: now, 138 data: json!({"description": "test shard"}), 139 target_did: None, 140 ref_cids: vec![], 141 }, 142 ) 143 .await 144 .unwrap(); 145} 146 147#[tokio::test] 148async fn test_list_channels_returns_correct_structure() { 149 let base_url = common::base_url().await; 150 let pool = common::get_db_pool().await; 151 let client = common::client(); 152 153 let test_did = "did:plc:test_channels_structure"; 154 insert_test_account(&pool, test_did).await; 155 insert_test_channel(&pool, "bafychannel001", test_did, "Test Channel").await; 156 157 let res = client 158 .get(format!( 159 "{}/xrpc/systems.gmstn.development.channel.listChannels?author={}", 160 base_url, test_did 161 )) 162 .send() 163 .await 164 .unwrap(); 165 166 assert_eq!(res.status(), StatusCode::OK); 167 168 let body: Value = res.json().await.unwrap(); 169 assert!(body["channels"].is_array()); 170 171 let channels = body["channels"].as_array().unwrap(); 172 assert!(!channels.is_empty()); 173 174 let channel = &channels[0]; 175 assert!(channel["uri"].is_string()); 176 assert!(channel["cid"].is_string()); 177 assert!(channel["displayName"].is_string()); 178 assert!(channel["createdAt"].is_string()); 179 assert!(channel["indexedAt"].is_string()); 180} 181 182#[tokio::test] 183async fn test_list_channels_empty_author() { 184 let base_url = common::base_url().await; 185 let client = common::client(); 186 187 let res = client 188 .get(format!( 189 "{}/xrpc/systems.gmstn.development.channel.listChannels?author=did:plc:nonexistent", 190 base_url 191 )) 192 .send() 193 .await 194 .unwrap(); 195 196 assert_eq!(res.status(), StatusCode::OK); 197 198 let body: Value = res.json().await.unwrap(); 199 assert!(body["channels"].is_array()); 200 assert!(body["channels"].as_array().unwrap().is_empty()); 201 assert!(body["cursor"].is_null()); 202} 203 204#[tokio::test] 205async fn test_list_channels_limit_bounds() { 206 let base_url = common::base_url().await; 207 let pool = common::get_db_pool().await; 208 let client = common::client(); 209 210 let test_did = "did:plc:test_limit_bounds"; 211 insert_test_account(&pool, test_did).await; 212 213 for i in 0..5 { 214 insert_test_channel(&pool, &format!("bafylimitchan{}", i), test_did, &format!("Channel {}", i)) 215 .await; 216 } 217 218 let res = client 219 .get(format!( 220 "{}/xrpc/systems.gmstn.development.channel.listChannels?author={}&limit=2", 221 base_url, test_did 222 )) 223 .send() 224 .await 225 .unwrap(); 226 227 assert_eq!(res.status(), StatusCode::OK); 228 229 let body: Value = res.json().await.unwrap(); 230 let channels = body["channels"].as_array().unwrap(); 231 assert_eq!(channels.len(), 2); 232 assert!(body["cursor"].is_string()); 233 234 let res_over_limit = client 235 .get(format!( 236 "{}/xrpc/systems.gmstn.development.channel.listChannels?author={}&limit=150", 237 base_url, test_did 238 )) 239 .send() 240 .await 241 .unwrap(); 242 243 assert_eq!(res_over_limit.status(), StatusCode::OK); 244 245 let body_over: Value = res_over_limit.json().await.unwrap(); 246 let channels_over = body_over["channels"].as_array().unwrap(); 247 assert!(channels_over.len() <= 100); 248} 249 250#[tokio::test] 251async fn test_list_invites_by_recipient() { 252 let base_url = common::base_url().await; 253 let pool = common::get_db_pool().await; 254 let client = common::client(); 255 256 let creator_did = "did:plc:invite_creator"; 257 let recipient_did = "did:plc:invite_recipient"; 258 insert_test_account(&pool, creator_did).await; 259 insert_test_account(&pool, recipient_did).await; 260 261 insert_test_invite(&pool, "bafyinvite001", creator_did, "bafyinvitechan001", recipient_did).await; 262 263 let res = client 264 .get(format!( 265 "{}/xrpc/systems.gmstn.development.channel.listInvites?recipient={}", 266 base_url, recipient_did 267 )) 268 .send() 269 .await 270 .unwrap(); 271 272 assert_eq!(res.status(), StatusCode::OK); 273 274 let body: Value = res.json().await.unwrap(); 275 assert!(body["invites"].is_array()); 276 277 let invites = body["invites"].as_array().unwrap(); 278 assert!(!invites.is_empty()); 279 280 let invite = &invites[0]; 281 assert!(invite["uri"].is_string()); 282 assert!(invite["cid"].is_string()); 283 assert!(invite["channel"].is_string()); 284 assert!(invite["recipient"].is_string()); 285 assert!(invite["createdAt"].is_string()); 286} 287 288#[tokio::test] 289async fn test_list_memberships_by_recipient() { 290 let base_url = common::base_url().await; 291 let pool = common::get_db_pool().await; 292 let client = common::client(); 293 294 let creator_did = "did:plc:membership_creator"; 295 let recipient_did = "did:plc:membership_recipient"; 296 insert_test_account(&pool, creator_did).await; 297 insert_test_account(&pool, recipient_did).await; 298 299 insert_test_membership(&pool, "bafymem001", recipient_did, "bafymemchan001", "bafymeminvite001").await; 300 301 let res = client 302 .get(format!( 303 "{}/xrpc/systems.gmstn.development.channel.listMemberships?recipient={}", 304 base_url, recipient_did 305 )) 306 .send() 307 .await 308 .unwrap(); 309 310 assert_eq!(res.status(), StatusCode::OK); 311 312 let body: Value = res.json().await.unwrap(); 313 assert!(body["memberships"].is_array()); 314 315 let memberships = body["memberships"].as_array().unwrap(); 316 assert!(!memberships.is_empty()); 317 318 let membership = &memberships[0]; 319 assert!(membership["uri"].is_string()); 320 assert!(membership["cid"].is_string()); 321 assert!(membership["channel"].is_string()); 322 assert!(membership["invite"].is_string()); 323 assert!(membership["recipient"].is_string()); 324 assert!(membership["state"].is_string()); 325 assert!(membership["createdAt"].is_string()); 326} 327 328#[tokio::test] 329async fn test_list_lattices_by_author() { 330 let base_url = common::base_url().await; 331 let pool = common::get_db_pool().await; 332 let client = common::client(); 333 334 let test_did = "did:plc:lattice_author"; 335 insert_test_account(&pool, test_did).await; 336 insert_test_lattice(&pool, "bafylattice001", test_did).await; 337 338 let res = client 339 .get(format!( 340 "{}/xrpc/systems.gmstn.development.lattice.listLattices?author={}", 341 base_url, test_did 342 )) 343 .send() 344 .await 345 .unwrap(); 346 347 assert_eq!(res.status(), StatusCode::OK); 348 349 let body: Value = res.json().await.unwrap(); 350 assert!(body["lattices"].is_array()); 351 352 let lattices = body["lattices"].as_array().unwrap(); 353 assert!(!lattices.is_empty()); 354 355 let lattice = &lattices[0]; 356 assert!(lattice["uri"].is_string()); 357 assert!(lattice["cid"].is_string()); 358 assert!(lattice["author"].is_string()); 359 assert!(lattice["createdAt"].is_string()); 360 assert!(lattice["indexedAt"].is_string()); 361} 362 363#[tokio::test] 364async fn test_list_shards_by_author() { 365 let base_url = common::base_url().await; 366 let pool = common::get_db_pool().await; 367 let client = common::client(); 368 369 let test_did = "did:plc:shard_author"; 370 insert_test_account(&pool, test_did).await; 371 insert_test_shard(&pool, "bafyshard001", test_did).await; 372 373 let res = client 374 .get(format!( 375 "{}/xrpc/systems.gmstn.development.shard.listShards?author={}", 376 base_url, test_did 377 )) 378 .send() 379 .await 380 .unwrap(); 381 382 assert_eq!(res.status(), StatusCode::OK); 383 384 let body: Value = res.json().await.unwrap(); 385 assert!(body["shards"].is_array()); 386 387 let shards = body["shards"].as_array().unwrap(); 388 assert!(!shards.is_empty()); 389 390 let shard = &shards[0]; 391 assert!(shard["uri"].is_string()); 392 assert!(shard["cid"].is_string()); 393 assert!(shard["author"].is_string()); 394 assert!(shard["createdAt"].is_string()); 395 assert!(shard["indexedAt"].is_string()); 396}