lib.rs 22 KB

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