lib.rs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881
  1. use std::collections::HashMap;
  2. use std::convert::TryFrom;
  3. use std::env::temp_dir;
  4. use std::path::PathBuf;
  5. use std::sync::Arc;
  6. use bytes::Bytes;
  7. use nanoid::nanoid;
  8. use parking_lot::RwLock;
  9. use protobuf::ProtobufError;
  10. use tokio::sync::broadcast::{channel, Sender};
  11. use uuid::Uuid;
  12. use flowy_core::{AppFlowyCore, AppFlowyCoreConfig};
  13. use flowy_database2::entities::*;
  14. use flowy_database2::event_map::DatabaseEvent;
  15. use flowy_document2::entities::{DocumentDataPB, OpenDocumentPayloadPB};
  16. use flowy_document2::event_map::DocumentEvent;
  17. use flowy_folder2::entities::icon::UpdateViewIconPayloadPB;
  18. use flowy_folder2::entities::*;
  19. use flowy_folder2::event_map::FolderEvent;
  20. use flowy_notification::entities::SubscribeObject;
  21. use flowy_notification::{register_notification_sender, NotificationSender};
  22. use flowy_server::supabase::define::{USER_DEVICE_ID, USER_EMAIL, USER_UUID};
  23. use flowy_user::entities::{
  24. AuthTypePB, ThirdPartyAuthPB, UpdateCloudConfigPB, UserCloudConfigPB, UserProfilePB,
  25. };
  26. use flowy_user::errors::{FlowyError, FlowyResult};
  27. use flowy_user::event_map::UserEvent::*;
  28. use crate::document::document_event::OpenDocumentData;
  29. use crate::event_builder::EventBuilder;
  30. use crate::user_event::{async_sign_up, SignUpContext};
  31. pub mod document;
  32. pub mod event_builder;
  33. pub mod folder_event;
  34. pub mod user_event;
  35. #[derive(Clone)]
  36. pub struct FlowyCoreTest {
  37. auth_type: Arc<RwLock<AuthTypePB>>,
  38. inner: AppFlowyCore,
  39. #[allow(dead_code)]
  40. cleaner: Arc<Cleaner>,
  41. pub notification_sender: TestNotificationSender,
  42. }
  43. impl Default for FlowyCoreTest {
  44. fn default() -> Self {
  45. let temp_dir = temp_dir().join(nanoid!(6));
  46. std::fs::create_dir_all(&temp_dir).unwrap();
  47. Self::new_with_user_data_path(temp_dir, nanoid!(6))
  48. }
  49. }
  50. impl FlowyCoreTest {
  51. pub fn new() -> Self {
  52. Self::default()
  53. }
  54. pub fn new_with_user_data_path(path: PathBuf, name: String) -> Self {
  55. let config = AppFlowyCoreConfig::new(path.to_str().unwrap(), name).log_filter(
  56. "info",
  57. vec!["flowy_test".to_string(), "lib_dispatch".to_string()],
  58. );
  59. let inner = std::thread::spawn(|| AppFlowyCore::new(config))
  60. .join()
  61. .unwrap();
  62. let notification_sender = TestNotificationSender::new();
  63. let auth_type = Arc::new(RwLock::new(AuthTypePB::Local));
  64. register_notification_sender(notification_sender.clone());
  65. std::mem::forget(inner.dispatcher());
  66. Self {
  67. inner,
  68. auth_type,
  69. notification_sender,
  70. cleaner: Arc::new(Cleaner(path)),
  71. }
  72. }
  73. pub async fn enable_encryption(&self) -> String {
  74. let config = EventBuilder::new(self.clone())
  75. .event(GetCloudConfig)
  76. .async_send()
  77. .await
  78. .parse::<UserCloudConfigPB>();
  79. let update = UpdateCloudConfigPB {
  80. enable_sync: None,
  81. enable_encrypt: Some(true),
  82. };
  83. let error = EventBuilder::new(self.clone())
  84. .event(SetCloudConfig)
  85. .payload(update)
  86. .async_send()
  87. .await
  88. .error();
  89. assert!(error.is_none());
  90. config.encrypt_secret
  91. }
  92. pub async fn get_user_profile(&self) -> Result<UserProfilePB, FlowyError> {
  93. EventBuilder::new(self.clone())
  94. .event(GetUserProfile)
  95. .async_send()
  96. .await
  97. .try_parse::<UserProfilePB>()
  98. }
  99. pub async fn new_with_guest_user() -> Self {
  100. let test = Self::default();
  101. test.sign_up_as_guest().await;
  102. test
  103. }
  104. pub async fn sign_up_as_guest(&self) -> SignUpContext {
  105. async_sign_up(self.inner.dispatcher(), AuthTypePB::Local).await
  106. }
  107. pub async fn supabase_party_sign_up(&self) -> UserProfilePB {
  108. let map = third_party_sign_up_param(Uuid::new_v4().to_string());
  109. let payload = ThirdPartyAuthPB {
  110. map,
  111. auth_type: AuthTypePB::Supabase,
  112. };
  113. EventBuilder::new(self.clone())
  114. .event(ThirdPartyAuth)
  115. .payload(payload)
  116. .async_send()
  117. .await
  118. .parse::<UserProfilePB>()
  119. }
  120. pub async fn sign_out(&self) {
  121. EventBuilder::new(self.clone())
  122. .event(SignOut)
  123. .async_send()
  124. .await;
  125. }
  126. pub fn set_auth_type(&self, auth_type: AuthTypePB) {
  127. *self.auth_type.write() = auth_type;
  128. }
  129. pub async fn init_user(&self) -> UserProfilePB {
  130. self.sign_up_as_guest().await.user_profile
  131. }
  132. pub async fn third_party_sign_up_with_uuid(
  133. &self,
  134. uuid: &str,
  135. email: Option<String>,
  136. ) -> FlowyResult<UserProfilePB> {
  137. let mut map = HashMap::new();
  138. map.insert(USER_UUID.to_string(), uuid.to_string());
  139. map.insert(USER_DEVICE_ID.to_string(), uuid.to_string());
  140. map.insert(
  141. USER_EMAIL.to_string(),
  142. email.unwrap_or_else(|| format!("{}@appflowy.io", nanoid!(10))),
  143. );
  144. let payload = ThirdPartyAuthPB {
  145. map,
  146. auth_type: AuthTypePB::Supabase,
  147. };
  148. let user_profile = EventBuilder::new(self.clone())
  149. .event(ThirdPartyAuth)
  150. .payload(payload)
  151. .async_send()
  152. .await
  153. .try_parse::<UserProfilePB>()?;
  154. Ok(user_profile)
  155. }
  156. // Must sign up/ sign in first
  157. pub async fn get_current_workspace(&self) -> WorkspaceSettingPB {
  158. EventBuilder::new(self.clone())
  159. .event(FolderEvent::GetCurrentWorkspace)
  160. .async_send()
  161. .await
  162. .parse::<flowy_folder2::entities::WorkspaceSettingPB>()
  163. }
  164. pub async fn get_all_workspace_views(&self) -> Vec<ViewPB> {
  165. EventBuilder::new(self.clone())
  166. .event(FolderEvent::ReadWorkspaceViews)
  167. .async_send()
  168. .await
  169. .parse::<flowy_folder2::entities::RepeatedViewPB>()
  170. .items
  171. }
  172. pub async fn get_views(&self, parent_view_id: &str) -> ViewPB {
  173. EventBuilder::new(self.clone())
  174. .event(FolderEvent::ReadView)
  175. .payload(ViewIdPB {
  176. value: parent_view_id.to_string(),
  177. })
  178. .async_send()
  179. .await
  180. .parse::<flowy_folder2::entities::ViewPB>()
  181. }
  182. pub async fn delete_view(&self, view_id: &str) {
  183. let payload = RepeatedViewIdPB {
  184. items: vec![view_id.to_string()],
  185. };
  186. // delete the view. the view will be moved to trash
  187. EventBuilder::new(self.clone())
  188. .event(FolderEvent::DeleteView)
  189. .payload(payload)
  190. .async_send()
  191. .await;
  192. }
  193. pub async fn update_view(&self, changeset: UpdateViewPayloadPB) -> Option<FlowyError> {
  194. // delete the view. the view will be moved to trash
  195. EventBuilder::new(self.clone())
  196. .event(FolderEvent::UpdateView)
  197. .payload(changeset)
  198. .async_send()
  199. .await
  200. .error()
  201. }
  202. pub async fn update_view_icon(&self, payload: UpdateViewIconPayloadPB) -> Option<FlowyError> {
  203. EventBuilder::new(self.clone())
  204. .event(FolderEvent::UpdateViewIcon)
  205. .payload(payload)
  206. .async_send()
  207. .await
  208. .error()
  209. }
  210. pub async fn create_view(&self, parent_id: &str, name: String) -> ViewPB {
  211. let payload = CreateViewPayloadPB {
  212. parent_view_id: parent_id.to_string(),
  213. name,
  214. desc: "".to_string(),
  215. thumbnail: None,
  216. layout: Default::default(),
  217. initial_data: vec![],
  218. meta: Default::default(),
  219. set_as_current: false,
  220. index: None,
  221. };
  222. EventBuilder::new(self.clone())
  223. .event(FolderEvent::CreateView)
  224. .payload(payload)
  225. .async_send()
  226. .await
  227. .parse::<flowy_folder2::entities::ViewPB>()
  228. }
  229. pub async fn create_document(
  230. &self,
  231. parent_id: &str,
  232. name: &str,
  233. initial_data: Vec<u8>,
  234. ) -> ViewPB {
  235. let payload = CreateViewPayloadPB {
  236. parent_view_id: parent_id.to_string(),
  237. name: name.to_string(),
  238. desc: "".to_string(),
  239. thumbnail: None,
  240. layout: ViewLayoutPB::Document,
  241. initial_data,
  242. meta: Default::default(),
  243. set_as_current: true,
  244. index: None,
  245. };
  246. let view = EventBuilder::new(self.clone())
  247. .event(FolderEvent::CreateView)
  248. .payload(payload)
  249. .async_send()
  250. .await
  251. .parse::<ViewPB>();
  252. let payload = OpenDocumentPayloadPB {
  253. document_id: view.id.clone(),
  254. };
  255. let _ = EventBuilder::new(self.clone())
  256. .event(DocumentEvent::OpenDocument)
  257. .payload(payload)
  258. .async_send()
  259. .await
  260. .parse::<DocumentDataPB>();
  261. view
  262. }
  263. pub async fn create_grid(&self, parent_id: &str, name: String, initial_data: Vec<u8>) -> ViewPB {
  264. let payload = CreateViewPayloadPB {
  265. parent_view_id: parent_id.to_string(),
  266. name,
  267. desc: "".to_string(),
  268. thumbnail: None,
  269. layout: ViewLayoutPB::Grid,
  270. initial_data,
  271. meta: Default::default(),
  272. set_as_current: true,
  273. index: None,
  274. };
  275. EventBuilder::new(self.clone())
  276. .event(FolderEvent::CreateView)
  277. .payload(payload)
  278. .async_send()
  279. .await
  280. .parse::<flowy_folder2::entities::ViewPB>()
  281. }
  282. pub async fn open_database(&self, view_id: &str) {
  283. EventBuilder::new(self.clone())
  284. .event(DatabaseEvent::GetDatabase)
  285. .payload(DatabaseViewIdPB {
  286. value: view_id.to_string(),
  287. })
  288. .async_send()
  289. .await;
  290. }
  291. pub async fn open_document(&self, doc_id: String) -> OpenDocumentData {
  292. let payload = OpenDocumentPayloadPB {
  293. document_id: doc_id.clone(),
  294. };
  295. let data = EventBuilder::new(self.clone())
  296. .event(DocumentEvent::OpenDocument)
  297. .payload(payload)
  298. .async_send()
  299. .await
  300. .parse::<DocumentDataPB>();
  301. OpenDocumentData { id: doc_id, data }
  302. }
  303. pub async fn create_board(&self, parent_id: &str, name: String, initial_data: Vec<u8>) -> ViewPB {
  304. let payload = CreateViewPayloadPB {
  305. parent_view_id: parent_id.to_string(),
  306. name,
  307. desc: "".to_string(),
  308. thumbnail: None,
  309. layout: ViewLayoutPB::Board,
  310. initial_data,
  311. meta: Default::default(),
  312. set_as_current: true,
  313. index: None,
  314. };
  315. EventBuilder::new(self.clone())
  316. .event(FolderEvent::CreateView)
  317. .payload(payload)
  318. .async_send()
  319. .await
  320. .parse::<flowy_folder2::entities::ViewPB>()
  321. }
  322. pub async fn create_calendar(
  323. &self,
  324. parent_id: &str,
  325. name: String,
  326. initial_data: Vec<u8>,
  327. ) -> ViewPB {
  328. let payload = CreateViewPayloadPB {
  329. parent_view_id: parent_id.to_string(),
  330. name,
  331. desc: "".to_string(),
  332. thumbnail: None,
  333. layout: ViewLayoutPB::Calendar,
  334. initial_data,
  335. meta: Default::default(),
  336. set_as_current: true,
  337. index: None,
  338. };
  339. EventBuilder::new(self.clone())
  340. .event(FolderEvent::CreateView)
  341. .payload(payload)
  342. .async_send()
  343. .await
  344. .parse::<flowy_folder2::entities::ViewPB>()
  345. }
  346. pub async fn get_database(&self, view_id: &str) -> DatabasePB {
  347. EventBuilder::new(self.clone())
  348. .event(DatabaseEvent::GetDatabase)
  349. .payload(DatabaseViewIdPB {
  350. value: view_id.to_string(),
  351. })
  352. .async_send()
  353. .await
  354. .parse::<flowy_database2::entities::DatabasePB>()
  355. }
  356. pub async fn get_all_database_fields(&self, view_id: &str) -> RepeatedFieldPB {
  357. EventBuilder::new(self.clone())
  358. .event(DatabaseEvent::GetFields)
  359. .payload(GetFieldPayloadPB {
  360. view_id: view_id.to_string(),
  361. field_ids: None,
  362. })
  363. .async_send()
  364. .await
  365. .parse::<RepeatedFieldPB>()
  366. }
  367. pub async fn create_field(&self, view_id: &str, field_type: FieldType) -> FieldPB {
  368. EventBuilder::new(self.clone())
  369. .event(DatabaseEvent::CreateTypeOption)
  370. .payload(CreateFieldPayloadPB {
  371. view_id: view_id.to_string(),
  372. field_type,
  373. type_option_data: None,
  374. })
  375. .async_send()
  376. .await
  377. .parse::<TypeOptionPB>()
  378. .field
  379. }
  380. pub async fn update_field(&self, changeset: FieldChangesetPB) {
  381. EventBuilder::new(self.clone())
  382. .event(DatabaseEvent::UpdateField)
  383. .payload(changeset)
  384. .async_send()
  385. .await;
  386. }
  387. pub async fn delete_field(&self, view_id: &str, field_id: &str) -> Option<FlowyError> {
  388. EventBuilder::new(self.clone())
  389. .event(DatabaseEvent::DeleteField)
  390. .payload(DeleteFieldPayloadPB {
  391. view_id: view_id.to_string(),
  392. field_id: field_id.to_string(),
  393. })
  394. .async_send()
  395. .await
  396. .error()
  397. }
  398. pub async fn update_field_type(
  399. &self,
  400. view_id: &str,
  401. field_id: &str,
  402. field_type: FieldType,
  403. ) -> Option<FlowyError> {
  404. EventBuilder::new(self.clone())
  405. .event(DatabaseEvent::UpdateFieldType)
  406. .payload(UpdateFieldTypePayloadPB {
  407. view_id: view_id.to_string(),
  408. field_id: field_id.to_string(),
  409. field_type,
  410. })
  411. .async_send()
  412. .await
  413. .error()
  414. }
  415. pub async fn duplicate_field(&self, view_id: &str, field_id: &str) -> Option<FlowyError> {
  416. EventBuilder::new(self.clone())
  417. .event(DatabaseEvent::DuplicateField)
  418. .payload(DuplicateFieldPayloadPB {
  419. view_id: view_id.to_string(),
  420. field_id: field_id.to_string(),
  421. })
  422. .async_send()
  423. .await
  424. .error()
  425. }
  426. pub async fn get_primary_field(&self, database_view_id: &str) -> FieldPB {
  427. EventBuilder::new(self.clone())
  428. .event(DatabaseEvent::GetPrimaryField)
  429. .payload(DatabaseViewIdPB {
  430. value: database_view_id.to_string(),
  431. })
  432. .async_send()
  433. .await
  434. .parse::<FieldPB>()
  435. }
  436. pub async fn create_row(
  437. &self,
  438. view_id: &str,
  439. start_row_id: Option<String>,
  440. data: Option<RowDataPB>,
  441. ) -> RowMetaPB {
  442. EventBuilder::new(self.clone())
  443. .event(DatabaseEvent::CreateRow)
  444. .payload(CreateRowPayloadPB {
  445. view_id: view_id.to_string(),
  446. start_row_id,
  447. group_id: None,
  448. data,
  449. })
  450. .async_send()
  451. .await
  452. .parse::<RowMetaPB>()
  453. }
  454. pub async fn delete_row(&self, view_id: &str, row_id: &str) -> Option<FlowyError> {
  455. EventBuilder::new(self.clone())
  456. .event(DatabaseEvent::DeleteRow)
  457. .payload(RowIdPB {
  458. view_id: view_id.to_string(),
  459. row_id: row_id.to_string(),
  460. group_id: None,
  461. })
  462. .async_send()
  463. .await
  464. .error()
  465. }
  466. pub async fn get_row(&self, view_id: &str, row_id: &str) -> OptionalRowPB {
  467. EventBuilder::new(self.clone())
  468. .event(DatabaseEvent::GetRow)
  469. .payload(RowIdPB {
  470. view_id: view_id.to_string(),
  471. row_id: row_id.to_string(),
  472. group_id: None,
  473. })
  474. .async_send()
  475. .await
  476. .parse::<OptionalRowPB>()
  477. }
  478. pub async fn get_row_meta(&self, view_id: &str, row_id: &str) -> RowMetaPB {
  479. EventBuilder::new(self.clone())
  480. .event(DatabaseEvent::GetRowMeta)
  481. .payload(RowIdPB {
  482. view_id: view_id.to_string(),
  483. row_id: row_id.to_string(),
  484. group_id: None,
  485. })
  486. .async_send()
  487. .await
  488. .parse::<RowMetaPB>()
  489. }
  490. pub async fn update_row_meta(&self, changeset: UpdateRowMetaChangesetPB) -> Option<FlowyError> {
  491. EventBuilder::new(self.clone())
  492. .event(DatabaseEvent::UpdateRowMeta)
  493. .payload(changeset)
  494. .async_send()
  495. .await
  496. .error()
  497. }
  498. pub async fn duplicate_row(&self, view_id: &str, row_id: &str) -> Option<FlowyError> {
  499. EventBuilder::new(self.clone())
  500. .event(DatabaseEvent::DuplicateRow)
  501. .payload(RowIdPB {
  502. view_id: view_id.to_string(),
  503. row_id: row_id.to_string(),
  504. group_id: None,
  505. })
  506. .async_send()
  507. .await
  508. .error()
  509. }
  510. pub async fn move_row(&self, view_id: &str, row_id: &str, to_row_id: &str) -> Option<FlowyError> {
  511. EventBuilder::new(self.clone())
  512. .event(DatabaseEvent::MoveRow)
  513. .payload(MoveRowPayloadPB {
  514. view_id: view_id.to_string(),
  515. from_row_id: row_id.to_string(),
  516. to_row_id: to_row_id.to_string(),
  517. })
  518. .async_send()
  519. .await
  520. .error()
  521. }
  522. pub async fn update_cell(&self, changeset: CellChangesetPB) -> Option<FlowyError> {
  523. EventBuilder::new(self.clone())
  524. .event(DatabaseEvent::UpdateCell)
  525. .payload(changeset)
  526. .async_send()
  527. .await
  528. .error()
  529. }
  530. pub async fn update_date_cell(&self, changeset: DateChangesetPB) -> Option<FlowyError> {
  531. EventBuilder::new(self.clone())
  532. .event(DatabaseEvent::UpdateDateCell)
  533. .payload(changeset)
  534. .async_send()
  535. .await
  536. .error()
  537. }
  538. pub async fn get_cell(&self, view_id: &str, row_id: &str, field_id: &str) -> CellPB {
  539. EventBuilder::new(self.clone())
  540. .event(DatabaseEvent::GetCell)
  541. .payload(CellIdPB {
  542. view_id: view_id.to_string(),
  543. row_id: row_id.to_string(),
  544. field_id: field_id.to_string(),
  545. })
  546. .async_send()
  547. .await
  548. .parse::<CellPB>()
  549. }
  550. pub async fn get_date_cell(&self, view_id: &str, row_id: &str, field_id: &str) -> DateCellDataPB {
  551. let cell = self.get_cell(view_id, row_id, field_id).await;
  552. DateCellDataPB::try_from(Bytes::from(cell.data)).unwrap()
  553. }
  554. pub async fn get_checklist_cell(
  555. &self,
  556. view_id: &str,
  557. field_id: &str,
  558. row_id: &str,
  559. ) -> ChecklistCellDataPB {
  560. EventBuilder::new(self.clone())
  561. .event(DatabaseEvent::GetChecklistCellData)
  562. .payload(CellIdPB {
  563. view_id: view_id.to_string(),
  564. row_id: row_id.to_string(),
  565. field_id: field_id.to_string(),
  566. })
  567. .async_send()
  568. .await
  569. .parse::<ChecklistCellDataPB>()
  570. }
  571. pub async fn update_checklist_cell(
  572. &self,
  573. changeset: ChecklistCellDataChangesetPB,
  574. ) -> Option<FlowyError> {
  575. EventBuilder::new(self.clone())
  576. .event(DatabaseEvent::UpdateChecklistCell)
  577. .payload(changeset)
  578. .async_send()
  579. .await
  580. .error()
  581. }
  582. pub async fn insert_option(
  583. &self,
  584. view_id: &str,
  585. field_id: &str,
  586. row_id: &str,
  587. name: &str,
  588. ) -> Option<FlowyError> {
  589. let option = EventBuilder::new(self.clone())
  590. .event(DatabaseEvent::CreateSelectOption)
  591. .payload(CreateSelectOptionPayloadPB {
  592. field_id: field_id.to_string(),
  593. view_id: view_id.to_string(),
  594. option_name: name.to_string(),
  595. })
  596. .async_send()
  597. .await
  598. .parse::<SelectOptionPB>();
  599. EventBuilder::new(self.clone())
  600. .event(DatabaseEvent::InsertOrUpdateSelectOption)
  601. .payload(RepeatedSelectOptionPayload {
  602. view_id: view_id.to_string(),
  603. field_id: field_id.to_string(),
  604. row_id: row_id.to_string(),
  605. items: vec![option],
  606. })
  607. .async_send()
  608. .await
  609. .error()
  610. }
  611. pub async fn get_groups(&self, view_id: &str) -> Vec<GroupPB> {
  612. EventBuilder::new(self.clone())
  613. .event(DatabaseEvent::GetGroups)
  614. .payload(DatabaseViewIdPB {
  615. value: view_id.to_string(),
  616. })
  617. .async_send()
  618. .await
  619. .parse::<RepeatedGroupPB>()
  620. .items
  621. }
  622. pub async fn move_group(&self, view_id: &str, from_id: &str, to_id: &str) -> Option<FlowyError> {
  623. EventBuilder::new(self.clone())
  624. .event(DatabaseEvent::MoveGroup)
  625. .payload(MoveGroupPayloadPB {
  626. view_id: view_id.to_string(),
  627. from_group_id: from_id.to_string(),
  628. to_group_id: to_id.to_string(),
  629. })
  630. .async_send()
  631. .await
  632. .error()
  633. }
  634. pub async fn set_group_by_field(&self, view_id: &str, field_id: &str) -> Option<FlowyError> {
  635. EventBuilder::new(self.clone())
  636. .event(DatabaseEvent::SetGroupByField)
  637. .payload(GroupByFieldPayloadPB {
  638. field_id: field_id.to_string(),
  639. view_id: view_id.to_string(),
  640. })
  641. .async_send()
  642. .await
  643. .error()
  644. }
  645. pub async fn update_group(
  646. &self,
  647. view_id: &str,
  648. group_id: &str,
  649. name: Option<String>,
  650. visible: Option<bool>,
  651. ) -> Option<FlowyError> {
  652. EventBuilder::new(self.clone())
  653. .event(DatabaseEvent::UpdateGroup)
  654. .payload(UpdateGroupPB {
  655. view_id: view_id.to_string(),
  656. group_id: group_id.to_string(),
  657. name,
  658. visible,
  659. })
  660. .async_send()
  661. .await
  662. .error()
  663. }
  664. pub async fn update_setting(&self, changeset: DatabaseSettingChangesetPB) -> Option<FlowyError> {
  665. EventBuilder::new(self.clone())
  666. .event(DatabaseEvent::UpdateDatabaseSetting)
  667. .payload(changeset)
  668. .async_send()
  669. .await
  670. .error()
  671. }
  672. pub async fn get_all_calendar_events(&self, view_id: &str) -> Vec<CalendarEventPB> {
  673. EventBuilder::new(self.clone())
  674. .event(DatabaseEvent::GetAllCalendarEvents)
  675. .payload(CalendarEventRequestPB {
  676. view_id: view_id.to_string(),
  677. })
  678. .async_send()
  679. .await
  680. .parse::<RepeatedCalendarEventPB>()
  681. .items
  682. }
  683. pub async fn get_view(&self, view_id: &str) -> ViewPB {
  684. EventBuilder::new(self.clone())
  685. .event(FolderEvent::ReadView)
  686. .payload(ViewIdPB {
  687. value: view_id.to_string(),
  688. })
  689. .async_send()
  690. .await
  691. .parse::<flowy_folder2::entities::ViewPB>()
  692. }
  693. }
  694. impl std::ops::Deref for FlowyCoreTest {
  695. type Target = AppFlowyCore;
  696. fn deref(&self) -> &Self::Target {
  697. &self.inner
  698. }
  699. }
  700. #[derive(Clone)]
  701. pub struct TestNotificationSender {
  702. sender: Arc<Sender<SubscribeObject>>,
  703. }
  704. impl Default for TestNotificationSender {
  705. fn default() -> Self {
  706. let (sender, _) = channel(1000);
  707. Self {
  708. sender: Arc::new(sender),
  709. }
  710. }
  711. }
  712. impl TestNotificationSender {
  713. pub fn new() -> Self {
  714. Self::default()
  715. }
  716. pub fn subscribe<T>(&self, id: &str, ty: impl Into<i32> + Send) -> tokio::sync::mpsc::Receiver<T>
  717. where
  718. T: TryFrom<Bytes, Error = ProtobufError> + Send + 'static,
  719. {
  720. let id = id.to_string();
  721. let (tx, rx) = tokio::sync::mpsc::channel::<T>(10);
  722. let mut receiver = self.sender.subscribe();
  723. let ty = ty.into();
  724. tokio::spawn(async move {
  725. // DatabaseNotification::DidUpdateDatabaseSnapshotState
  726. while let Ok(value) = receiver.recv().await {
  727. if value.id == id && value.ty == ty {
  728. if let Some(payload) = value.payload {
  729. match T::try_from(Bytes::from(payload)) {
  730. Ok(object) => {
  731. let _ = tx.send(object).await;
  732. },
  733. Err(e) => {
  734. panic!(
  735. "Failed to parse notification payload to type: {:?} with error: {}",
  736. std::any::type_name::<T>(),
  737. e
  738. );
  739. },
  740. }
  741. }
  742. }
  743. }
  744. });
  745. rx
  746. }
  747. pub fn subscribe_with_condition<T, F>(&self, id: &str, when: F) -> tokio::sync::mpsc::Receiver<T>
  748. where
  749. T: TryFrom<Bytes, Error = ProtobufError> + Send + 'static,
  750. F: Fn(&T) -> bool + Send + 'static,
  751. {
  752. let id = id.to_string();
  753. let (tx, rx) = tokio::sync::mpsc::channel::<T>(10);
  754. let mut receiver = self.sender.subscribe();
  755. tokio::spawn(async move {
  756. while let Ok(value) = receiver.recv().await {
  757. if value.id == id {
  758. if let Some(payload) = value.payload {
  759. if let Ok(object) = T::try_from(Bytes::from(payload)) {
  760. if when(&object) {
  761. let _ = tx.send(object).await;
  762. }
  763. }
  764. }
  765. }
  766. }
  767. });
  768. rx
  769. }
  770. }
  771. impl NotificationSender for TestNotificationSender {
  772. fn send_subject(&self, subject: SubscribeObject) -> Result<(), String> {
  773. let _ = self.sender.send(subject);
  774. Ok(())
  775. }
  776. }
  777. pub struct Cleaner(PathBuf);
  778. impl Cleaner {
  779. pub fn new(dir: PathBuf) -> Self {
  780. Cleaner(dir)
  781. }
  782. fn cleanup(dir: &PathBuf) {
  783. let _ = std::fs::remove_dir_all(dir);
  784. }
  785. }
  786. impl Drop for Cleaner {
  787. fn drop(&mut self) {
  788. Self::cleanup(&self.0)
  789. }
  790. }
  791. pub fn third_party_sign_up_param(uuid: String) -> HashMap<String, String> {
  792. let mut params = HashMap::new();
  793. params.insert(USER_UUID.to_string(), uuid);
  794. params.insert(
  795. USER_EMAIL.to_string(),
  796. format!("{}@test.com", Uuid::new_v4()),
  797. );
  798. params.insert(USER_DEVICE_ID.to_string(), Uuid::new_v4().to_string());
  799. params
  800. }