use endr::Remote; use futures::{Future, FutureExt, StreamExt}; use tlpt::{DocID, InvitationKind, JMBLContent, Tlpt}; use jmbl::{Input, Value}; use litl::Val; use mofo::Mofo; use std::time::Duration; use tracing::{debug, trace}; macro_rules! timeout { ($f:expr) => { tokio::time::timeout(Duration::from_millis(500), $f).map(|r| r.expect("Timed out")) }; } #[tokio::test] async fn can_create_team_and_share_document_for_reading() { // traceful::init_test_trace(); let (_, _, background, setup_and_basic_assertions) = create_team_and_share_document(InvitationKind::Reader); background.run_until(setup_and_basic_assertions).await; } fn create_team_and_share_document( invitation_kind: InvitationKind, ) -> (Tlpt, Tlpt, Mofo, impl Future) { let background = Mofo::new(); let tlpt1 = Tlpt::new("tlpt1".to_string(), background.clone()); let tlpt2 = Tlpt::new("tlpt2".to_string(), background.clone()); let setup = { let tlpt1 = tlpt1.clone(); let tlpt2 = tlpt2.clone(); async move { let team = tlpt1.create_team().await; let doc = tlpt1.create_document( &team, JMBLContent::create(|mut view| view.create_map([( "test", Value::str("Hello World") )])), ) .await; assert_eq!( doc.content() .expect_jmbl() .current_root() .if_map() .unwrap() .val_to_litl(), Val::object([("test", Val::str("Hello World"))]) ); let invitation_token = team .create_invitation( invitation_kind, None, None, None, ti64::now() + 24 * 60 * 60 * 1000, ) .await .unwrap(); let (tlpt1_as_remote, tlpt2_as_remote) = Remote::new_connected_test_pair("tlpt1", "tlpt2"); tlpt1.add_remote(tlpt2_as_remote).await; tlpt2.add_remote(tlpt1_as_remote).await; let tlpt2 = tlpt2.clone(); debug!("invitation token: {:?}", invitation_token); tlpt2.join_team(invitation_token).await.unwrap(); let managed_doc2 = timeout!(tlpt2.load_document(doc.id())) .await .content() .expect_jmbl(); let doc2_updates = managed_doc2.updates("test2".to_owned()); let (first_root, _) = doc2_updates .filter(|(root, _)| { let is_null = root.if_plain() == Ok(&Val::null()); trace!(root = ?root, is_null = is_null, "Got root"); futures::future::ready(!is_null) }) .next() .await .unwrap(); assert_eq!( first_root.if_map().unwrap().val_to_litl(), Val::object([("test", Val::str("Hello World"))]) ); doc.id() } }; (tlpt1, tlpt2, background, setup) } #[tokio::test] async fn can_create_team_and_share_document_for_writing() { // traceful::init_test_trace(); let (tlpt1, tlpt2, background, setup_and_basic_assertions) = create_team_and_share_document(InvitationKind::Writer); background .run_until(async { // TODO: #70 wait until we definitely have write access, and make waiting for that easy let doc_id = setup_and_basic_assertions.await; let managed_doc2 = timeout!(tlpt2.load_document(doc_id.clone())) .await .content() .expect_jmbl(); let write_view = managed_doc2.start_writing(true); write_view .get_root() .if_map_mut() .unwrap() .insert("test2", "Litl World"); managed_doc2.finish_writing(write_view); assert_eq!( managed_doc2.current_root().if_map().unwrap().val_to_litl(), Val::object([ ("test", Val::str("Hello World")), ("test2", Val::str("Litl World")) ]) ); let managed_doc1 = timeout!(tlpt1.load_document(doc_id)) .await .content() .expect_jmbl(); let doc1_updates = managed_doc1.updates("test1_after_sharing".to_owned()); let (first_root_with_tlpt2_update, _) = timeout!(doc1_updates .filter(|(root, _)| { let has_update = root.if_map().unwrap().val_to_litl().get("test2").is_some(); trace!(root = ?root, has_update = has_update, "Got root"); futures::future::ready(has_update) }) .next()) .await .unwrap(); assert_eq!( first_root_with_tlpt2_update.if_map().unwrap().val_to_litl(), Val::object([ ("test", Val::str("Hello World")), ("test2", Val::str("Litl World")) ]) ); }) .await }