diff --git a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/errors.pbenum.dart b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/errors.pbenum.dart index 6ba6cfccba..caf87186ce 100644 --- a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/errors.pbenum.dart +++ b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/errors.pbenum.dart @@ -12,8 +12,8 @@ import 'package:protobuf/protobuf.dart' as $pb; class ErrorCode extends $pb.ProtobufEnum { static const ErrorCode Unknown = ErrorCode._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Unknown'); static const ErrorCode UserDatabaseInitFailed = ErrorCode._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserDatabaseInitFailed'); - static const ErrorCode UserDatabaseWriteLocked = ErrorCode._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserDatabaseWriteLocked'); - static const ErrorCode UserDatabaseReadLocked = ErrorCode._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserDatabaseReadLocked'); + static const ErrorCode AcquireWriteLockedFailed = ErrorCode._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'AcquireWriteLockedFailed'); + static const ErrorCode AcquireReadLockedFailed = ErrorCode._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'AcquireReadLockedFailed'); static const ErrorCode UserDatabaseDidNotMatch = ErrorCode._(4, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserDatabaseDidNotMatch'); static const ErrorCode UserDatabaseInternalError = ErrorCode._(5, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserDatabaseInternalError'); static const ErrorCode SqlInternalError = ErrorCode._(6, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SqlInternalError'); @@ -41,8 +41,8 @@ class ErrorCode extends $pb.ProtobufEnum { static const $core.List values = [ Unknown, UserDatabaseInitFailed, - UserDatabaseWriteLocked, - UserDatabaseReadLocked, + AcquireWriteLockedFailed, + AcquireReadLockedFailed, UserDatabaseDidNotMatch, UserDatabaseInternalError, SqlInternalError, diff --git a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/errors.pbjson.dart b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/errors.pbjson.dart index 25bce0ca2c..3ec72ae7c0 100644 --- a/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/errors.pbjson.dart +++ b/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-user/errors.pbjson.dart @@ -14,8 +14,8 @@ const ErrorCode$json = const { '2': const [ const {'1': 'Unknown', '2': 0}, const {'1': 'UserDatabaseInitFailed', '2': 1}, - const {'1': 'UserDatabaseWriteLocked', '2': 2}, - const {'1': 'UserDatabaseReadLocked', '2': 3}, + const {'1': 'AcquireWriteLockedFailed', '2': 2}, + const {'1': 'AcquireReadLockedFailed', '2': 3}, const {'1': 'UserDatabaseDidNotMatch', '2': 4}, const {'1': 'UserDatabaseInternalError', '2': 5}, const {'1': 'SqlInternalError', '2': 6}, @@ -43,7 +43,7 @@ const ErrorCode$json = const { }; /// Descriptor for `ErrorCode`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List errorCodeDescriptor = $convert.base64Decode('CglFcnJvckNvZGUSCwoHVW5rbm93bhAAEhoKFlVzZXJEYXRhYmFzZUluaXRGYWlsZWQQARIbChdVc2VyRGF0YWJhc2VXcml0ZUxvY2tlZBACEhoKFlVzZXJEYXRhYmFzZVJlYWRMb2NrZWQQAxIbChdVc2VyRGF0YWJhc2VEaWROb3RNYXRjaBAEEh0KGVVzZXJEYXRhYmFzZUludGVybmFsRXJyb3IQBRIUChBTcWxJbnRlcm5hbEVycm9yEAYSGAoURGF0YWJhc2VDb25uZWN0RXJyb3IQBxITCg9Vc2VyTm90TG9naW5ZZXQQChIXChNSZWFkQ3VycmVudElkRmFpbGVkEAsSGAoUV3JpdGVDdXJyZW50SWRGYWlsZWQQDBIQCgxFbWFpbElzRW1wdHkQFBIWChJFbWFpbEZvcm1hdEludmFsaWQQFRIWChJFbWFpbEFscmVhZHlFeGlzdHMQFhITCg9QYXNzd29yZElzRW1wdHkQHhITCg9QYXNzd29yZFRvb0xvbmcQHxIkCiBQYXNzd29yZENvbnRhaW5zRm9yYmlkQ2hhcmFjdGVycxAgEhkKFVBhc3N3b3JkRm9ybWF0SW52YWxpZBAhEhQKEFBhc3N3b3JkTm90TWF0Y2gQIhITCg9Vc2VyTmFtZVRvb0xvbmcQKBInCiNVc2VyTmFtZUNvbnRhaW5zRm9yYmlkZGVuQ2hhcmFjdGVycxApEhMKD1VzZXJOYW1lSXNFbXB0eRAqEhgKFFVzZXJXb3Jrc3BhY2VJbnZhbGlkEDISEQoNVXNlcklkSW52YWxpZBAzEiAKHENyZWF0ZURlZmF1bHRXb3Jrc3BhY2VGYWlsZWQQNBIgChxEZWZhdWx0V29ya3NwYWNlQWxyZWFkeUV4aXN0EDUSDwoLU2VydmVyRXJyb3IQZA=='); +final $typed_data.Uint8List errorCodeDescriptor = $convert.base64Decode('CglFcnJvckNvZGUSCwoHVW5rbm93bhAAEhoKFlVzZXJEYXRhYmFzZUluaXRGYWlsZWQQARIcChhBY3F1aXJlV3JpdGVMb2NrZWRGYWlsZWQQAhIbChdBY3F1aXJlUmVhZExvY2tlZEZhaWxlZBADEhsKF1VzZXJEYXRhYmFzZURpZE5vdE1hdGNoEAQSHQoZVXNlckRhdGFiYXNlSW50ZXJuYWxFcnJvchAFEhQKEFNxbEludGVybmFsRXJyb3IQBhIYChREYXRhYmFzZUNvbm5lY3RFcnJvchAHEhMKD1VzZXJOb3RMb2dpbllldBAKEhcKE1JlYWRDdXJyZW50SWRGYWlsZWQQCxIYChRXcml0ZUN1cnJlbnRJZEZhaWxlZBAMEhAKDEVtYWlsSXNFbXB0eRAUEhYKEkVtYWlsRm9ybWF0SW52YWxpZBAVEhYKEkVtYWlsQWxyZWFkeUV4aXN0cxAWEhMKD1Bhc3N3b3JkSXNFbXB0eRAeEhMKD1Bhc3N3b3JkVG9vTG9uZxAfEiQKIFBhc3N3b3JkQ29udGFpbnNGb3JiaWRDaGFyYWN0ZXJzECASGQoVUGFzc3dvcmRGb3JtYXRJbnZhbGlkECESFAoQUGFzc3dvcmROb3RNYXRjaBAiEhMKD1VzZXJOYW1lVG9vTG9uZxAoEicKI1VzZXJOYW1lQ29udGFpbnNGb3JiaWRkZW5DaGFyYWN0ZXJzECkSEwoPVXNlck5hbWVJc0VtcHR5ECoSGAoUVXNlcldvcmtzcGFjZUludmFsaWQQMhIRCg1Vc2VySWRJbnZhbGlkEDMSIAocQ3JlYXRlRGVmYXVsdFdvcmtzcGFjZUZhaWxlZBA0EiAKHERlZmF1bHRXb3Jrc3BhY2VBbHJlYWR5RXhpc3QQNRIPCgtTZXJ2ZXJFcnJvchBk'); @$core.Deprecated('Use userErrorDescriptor instead') const UserError$json = const { '1': 'UserError', diff --git a/rust-lib/flowy-dispatch/Cargo.toml b/rust-lib/flowy-dispatch/Cargo.toml index e0cba0a5b7..36743cd158 100644 --- a/rust-lib/flowy-dispatch/Cargo.toml +++ b/rust-lib/flowy-dispatch/Cargo.toml @@ -24,6 +24,7 @@ dyn-clone = "1.0" derivative = "2.2.0" serde_json = {version = "1.0"} serde = { version = "1.0", features = ["derive"] } +dashmap = "4.0" #optional crate bincode = { version = "1.3", optional = true} diff --git a/rust-lib/flowy-dispatch/src/dispatch.rs b/rust-lib/flowy-dispatch/src/dispatch.rs index 8f474d0741..49d24f5693 100644 --- a/rust-lib/flowy-dispatch/src/dispatch.rs +++ b/rust-lib/flowy-dispatch/src/dispatch.rs @@ -14,7 +14,7 @@ use std::{future::Future, sync::RwLock}; use tokio::macros::support::{Pin, Poll}; lazy_static! { - pub static ref EVENT_DISPATCH: RwLock> = RwLock::new(None); + static ref EVENT_DISPATCH: RwLock> = RwLock::new(None); } pub struct EventDispatch { @@ -31,10 +31,7 @@ impl EventDispatch { log::trace!("{}", module_info(&modules)); let module_map = as_module_map(modules); let runtime = tokio_default_runtime().unwrap(); - let dispatch = EventDispatch { - module_map, - runtime, - }; + let dispatch = EventDispatch { module_map, runtime }; *(EVENT_DISPATCH.write().unwrap()) = Some(dispatch); } @@ -45,10 +42,7 @@ impl EventDispatch { EventDispatch::async_send_with_callback(request, |_| Box::pin(async {})) } - pub fn async_send_with_callback( - request: Req, - callback: Callback, - ) -> DispatchFuture + pub fn async_send_with_callback(request: Req, callback: Callback) -> DispatchFuture where Req: std::convert::Into, Callback: FnOnce(EventResponse) -> BoxFuture<'static, ()> + 'static + Send + Sync, @@ -74,10 +68,7 @@ impl EventDispatch { DispatchFuture { fut: Box::pin(async move { join_handle.await.unwrap_or_else(|e| { - let error = InternalError::JoinError(format!( - "EVENT_DISPATCH join error: {:?}", - e - )); + let error = InternalError::JoinError(format!("EVENT_DISPATCH join error: {:?}", e)); error.as_response() }) }), @@ -94,9 +85,7 @@ impl EventDispatch { } pub fn sync_send(request: ModuleRequest) -> EventResponse { - futures::executor::block_on(async { - EventDispatch::async_send_with_callback(request, |_| Box::pin(async {})).await - }) + futures::executor::block_on(async { EventDispatch::async_send_with_callback(request, |_| Box::pin(async {})).await }) } } @@ -120,8 +109,7 @@ where } } -pub type BoxFutureCallback = - Box BoxFuture<'static, ()> + 'static + Send + Sync>; +pub type BoxFutureCallback = Box BoxFuture<'static, ()> + 'static + Send + Sync>; #[derive(Derivative)] #[derivative(Debug)] diff --git a/rust-lib/flowy-document/tests/editor/doc_test.rs b/rust-lib/flowy-document/tests/editor/doc_test.rs index 5c57364fba..3e8bc49a4f 100644 --- a/rust-lib/flowy-document/tests/editor/doc_test.rs +++ b/rust-lib/flowy-document/tests/editor/doc_test.rs @@ -1,7 +1,9 @@ use crate::helper::*; +use flowy_test::builder::{TestBuilder, UserTestBuilder}; #[test] fn file_create_test() { + let _ = UserTestBuilder::new().sign_up(); let doc_desc = create_doc("hello world", "flutter ❤️ rust", "123"); dbg!(&doc_desc); @@ -11,6 +13,7 @@ fn file_create_test() { #[test] fn file_update_text_test() { + let _ = UserTestBuilder::new().sign_up(); let doc_desc = create_doc("hello world", "flutter ❤️ rust", ""); dbg!(&doc_desc); diff --git a/rust-lib/flowy-document/tests/editor/helper.rs b/rust-lib/flowy-document/tests/editor/helper.rs index a612d27f53..e989dabc9c 100644 --- a/rust-lib/flowy-document/tests/editor/helper.rs +++ b/rust-lib/flowy-document/tests/editor/helper.rs @@ -1,4 +1,4 @@ -use flowy_test::builder::AnnieTestBuilder; +use flowy_test::builder::{AnnieTestBuilder, DocTestBuilder, TestBuilder}; use flowy_document::{entities::doc::*, event::EditorEvent::*}; use flowy_infra::uuid; @@ -11,13 +11,12 @@ pub fn create_doc(name: &str, desc: &str, text: &str) -> DocInfo { text: text.to_owned(), }; - let doc_desc = AnnieTestBuilder::new() + let doc = DocTestBuilder::new() .event(CreateDoc) .request(request) .sync_send() .parse::(); - - doc_desc + doc } pub fn save_doc(desc: &DocInfo, content: &str) { @@ -28,34 +27,31 @@ pub fn save_doc(desc: &DocInfo, content: &str) { text: Some(content.to_owned()), }; - let _ = AnnieTestBuilder::new() - .event(UpdateDoc) - .request(request) - .sync_send(); + let _ = DocTestBuilder::new().event(UpdateDoc).request(request).sync_send(); } -#[allow(dead_code)] -pub fn read_doc(doc_id: &str) -> DocInfo { - let request = QueryDocRequest { - doc_id: doc_id.to_string(), - }; +// #[allow(dead_code)] +// pub fn read_doc(doc_id: &str) -> DocInfo { +// let request = QueryDocRequest { +// doc_id: doc_id.to_string(), +// }; +// +// let doc = AnnieTestBuilder::new() +// .event(ReadDocInfo) +// .request(request) +// .sync_send() +// .parse::(); +// +// doc +// } - let doc = AnnieTestBuilder::new() - .event(ReadDocInfo) - .request(request) - .sync_send() - .parse::(); - - doc -} - -pub fn read_doc_data(doc_id: &str, path: &str) -> DocData { +pub(crate) fn read_doc_data(doc_id: &str, path: &str) -> DocData { let request = QueryDocDataRequest { doc_id: doc_id.to_string(), path: path.to_string(), }; - let doc = AnnieTestBuilder::new() + let doc = DocTestBuilder::new() .event(ReadDocData) .request(request) .sync_send() diff --git a/rust-lib/flowy-test/Cargo.toml b/rust-lib/flowy-test/Cargo.toml index 959b935e90..5d52dd11e4 100644 --- a/rust-lib/flowy-test/Cargo.toml +++ b/rust-lib/flowy-test/Cargo.toml @@ -11,6 +11,7 @@ flowy-dispatch = { path = "../flowy-dispatch"} flowy-user = { path = "../flowy-user"} flowy-workspace = { path = "../flowy-workspace"} flowy-infra = { path = "../flowy-infra"} +flowy-document = { path = "../flowy-document"} serde = { version = "1.0", features = ["derive"] } bincode = { version = "1.3"} diff --git a/rust-lib/flowy-test/src/builder.rs b/rust-lib/flowy-test/src/builder.rs index 79ff484267..62c7e7c61a 100644 --- a/rust-lib/flowy-test/src/builder.rs +++ b/rust-lib/flowy-test/src/builder.rs @@ -6,45 +6,32 @@ use std::{ }; use crate::{ - helper::{create_default_workspace_if_need, valid_email}, + helper::{create_default_workspace_if_need, login_email, login_password}, + init_test_sdk, tester::{TesterContext, TesterTrait}, }; +use flowy_document::errors::DocError; use flowy_user::errors::UserError; use flowy_workspace::errors::WorkspaceError; use std::marker::PhantomData; -pub type AnnieTestBuilder = Builder>; -impl AnnieTestBuilder { - pub fn new() -> Self { - let mut builder = Builder::test(Box::new(FlowyAnnie::::new())); - builder.setup_default_workspace(); - builder - } - - pub fn setup_default_workspace(&mut self) { - self.login_if_need(); - let user_id = self.user_detail.as_ref().unwrap().id.clone(); - let _ = create_default_workspace_if_need(&user_id); - } +pub type WorkspaceTestBuilder = Builder>; +impl WorkspaceTestBuilder { + pub fn new() -> Self { Builder::test(Box::new(RandomUserTester::::new())) } } -pub type TestBuilder = Builder>; -impl TestBuilder { + +pub type DocTestBuilder = Builder>; +impl DocTestBuilder { + pub fn new() -> Self { Builder::test(Box::new(RandomUserTester::::new())) } +} + +pub type UserTestBuilder = Builder>; +impl UserTestBuilder { pub fn new() -> Self { Builder::test(Box::new(RandomUserTester::::new())) } -} -pub struct Builder { - pub tester: Box, - pub user_detail: Option, -} - -impl Builder -where - T: TesterTrait, -{ - fn test(tester: Box) -> Self { Self { tester, user_detail: None } } - - pub fn sign_up(self) -> SignUpContext { + pub fn sign_up(mut self) -> SignUpContext { let (user_detail, password) = self.tester.sign_up(); + let _ = create_default_workspace_if_need(&user_detail.id); SignUpContext { user_detail, password } } @@ -59,6 +46,23 @@ where self.user_detail = Some(user_detail); } + pub fn get_user_detail(&self) -> &Option { &self.user_detail } +} + +pub struct Builder { + pub tester: Box, + user_detail: Option, +} + +impl Builder +where + T: TesterTrait, +{ + fn test(tester: Box) -> Self { + init_test_sdk(); + Self { tester, user_detail: None } + } + pub fn request

(mut self, request: P) -> Self where P: ToBytes, @@ -128,34 +132,6 @@ where fn context(&self) -> &TesterContext { &self.context } } -pub struct FlowyAnnie { - context: TesterContext, - err_phantom: PhantomData, -} - -impl FlowyAnnie -where - Error: FromBytes + Debug, -{ - pub fn new() -> Self { - Self { - context: TesterContext::new(valid_email()), - err_phantom: PhantomData, - } - } -} - -impl TesterTrait for FlowyAnnie -where - Error: FromBytes + Debug, -{ - type Error = Error; - - fn mut_context(&mut self) -> &mut TesterContext { &mut self.context } - - fn context(&self) -> &TesterContext { &self.context } -} - pub struct SignUpContext { pub user_detail: UserDetail, pub password: String, diff --git a/rust-lib/flowy-test/src/helper.rs b/rust-lib/flowy-test/src/helper.rs index 23498f881f..0aeed8b56d 100644 --- a/rust-lib/flowy-test/src/helper.rs +++ b/rust-lib/flowy-test/src/helper.rs @@ -4,6 +4,7 @@ use flowy_infra::{kv::KV, uuid}; use flowy_user::errors::{ErrorBuilder, ErrorCode, UserError}; use flowy_workspace::{ entities::workspace::{CreateWorkspaceRequest, QueryWorkspaceRequest, Workspace}, + errors::WorkspaceError, event::WorkspaceEvent::{CreateWorkspace, OpenWorkspace}, }; use std::{fs, path::PathBuf}; @@ -26,9 +27,9 @@ pub fn root_dir() -> String { pub fn random_email() -> String { format!("{}@appflowy.io", uuid()) } -pub fn valid_email() -> String { "annie@appflowy.io".to_string() } +pub fn login_email() -> String { "annie@appflowy.io".to_string() } -pub fn valid_password() -> String { "HelloWorld!123".to_string() } +pub fn login_password() -> String { "HelloWorld!123".to_string() } const DEFAULT_WORKSPACE_NAME: &'static str = "My workspace"; const DEFAULT_WORKSPACE_DESC: &'static str = "This is your first workspace"; @@ -50,7 +51,7 @@ pub(crate) fn create_default_workspace_if_need(user_id: &str) -> Result<(), User let request = ModuleRequest::new(CreateWorkspace).payload(payload); let result = EventDispatch::sync_send(request) - .parse::() + .parse::() .map_err(|e| ErrorBuilder::new(ErrorCode::CreateDefaultWorkspaceFailed).error(e).build())?; let workspace = result.map_err(|e| ErrorBuilder::new(ErrorCode::CreateDefaultWorkspaceFailed).error(e).build())?; @@ -63,7 +64,7 @@ pub(crate) fn create_default_workspace_if_need(user_id: &str) -> Result<(), User let request = ModuleRequest::new(OpenWorkspace).payload(query); let _result = EventDispatch::sync_send(request) - .parse::() + .parse::() .unwrap() .unwrap(); diff --git a/rust-lib/flowy-test/src/lib.rs b/rust-lib/flowy-test/src/lib.rs index 389f1495ff..878c9d1c33 100644 --- a/rust-lib/flowy-test/src/lib.rs +++ b/rust-lib/flowy-test/src/lib.rs @@ -7,10 +7,7 @@ use flowy_sdk::FlowySDK; use std::sync::Once; pub mod prelude { - pub use crate::{ - builder::{TestBuilder, *}, - helper::*, - }; + pub use crate::{builder::*, helper::*}; pub use flowy_dispatch::prelude::*; } diff --git a/rust-lib/flowy-test/src/tester.rs b/rust-lib/flowy-test/src/tester.rs index 85d62086f9..8d2a3ebadc 100644 --- a/rust-lib/flowy-test/src/tester.rs +++ b/rust-lib/flowy-test/src/tester.rs @@ -1,5 +1,5 @@ use crate::{ - helper::{random_email, valid_password}, + helper::{login_password, random_email}, init_test_sdk, }; use flowy_dispatch::prelude::*; @@ -10,6 +10,7 @@ use flowy_user::{ prelude::*, }; +use crate::helper::login_email; use flowy_user::event::UserEvent::SignIn; use std::{ convert::TryFrom, @@ -22,15 +23,10 @@ pub struct TesterContext { request: Option, response: Option, status_code: StatusCode, - user_email: String, } impl TesterContext { - pub fn new(email: String) -> Self { - let mut ctx = TesterContext::default(); - ctx.user_email = email; - ctx - } + pub fn new(email: String) -> Self { TesterContext::default() } } impl std::default::Default for TesterContext { @@ -39,7 +35,6 @@ impl std::default::Default for TesterContext { request: None, status_code: StatusCode::Ok, response: None, - user_email: random_email(), } } } @@ -59,7 +54,6 @@ pub trait TesterTrait { where E: Eq + Hash + Debug + Clone + Display, { - init_test_sdk(); self.mut_context().request = Some(ModuleRequest::new(event)); } @@ -101,16 +95,13 @@ pub trait TesterTrait { fn error(&mut self) -> Self::Error { let response = self.mut_context().response.clone().unwrap(); assert_eq!(response.status_code, StatusCode::Err); - >::try_from(response.payload) - .unwrap() - .into_inner() + >::try_from(response.payload).unwrap().into_inner() } fn sign_up(&self) -> (UserDetail, String) { - init_test_sdk(); - let password = valid_password(); + let password = login_password(); let payload = SignUpRequest { - email: self.context().user_email.clone(), + email: random_email(), name: "app flowy".to_string(), password: password.clone(), } @@ -118,34 +109,26 @@ pub trait TesterTrait { .unwrap(); let request = ModuleRequest::new(SignUp).payload(payload); - let user_detail = EventDispatch::sync_send(request) - .parse::() - .unwrap() - .unwrap(); + let user_detail = EventDispatch::sync_send(request).parse::().unwrap().unwrap(); (user_detail, password) } fn sign_in(&self) -> UserDetail { - init_test_sdk(); let payload = SignInRequest { - email: self.context().user_email.clone(), - password: valid_password(), + email: login_email(), + password: login_password(), } .into_bytes() .unwrap(); let request = ModuleRequest::new(SignIn).payload(payload); - let user_detail = EventDispatch::sync_send(request) - .parse::() - .unwrap() - .unwrap(); + let user_detail = EventDispatch::sync_send(request).parse::().unwrap().unwrap(); user_detail } fn login_if_need(&self) -> UserDetail { - init_test_sdk(); match EventDispatch::sync_send(ModuleRequest::new(GetUserProfile)) .parse::() .unwrap() @@ -155,8 +138,5 @@ pub trait TesterTrait { } } - fn logout(&self) { - init_test_sdk(); - let _ = EventDispatch::sync_send(ModuleRequest::new(SignOut)); - } + fn logout(&self) { let _ = EventDispatch::sync_send(ModuleRequest::new(SignOut)); } } diff --git a/rust-lib/flowy-user/src/errors.rs b/rust-lib/flowy-user/src/errors.rs index f87d6a5ef3..db149b7ed8 100644 --- a/rust-lib/flowy-user/src/errors.rs +++ b/rust-lib/flowy-user/src/errors.rs @@ -27,10 +27,10 @@ pub enum ErrorCode { Unknown = 0, #[display(fmt = "Database init failed")] UserDatabaseInitFailed = 1, - #[display(fmt = "Get database write lock failed")] - UserDatabaseWriteLocked = 2, - #[display(fmt = "Get database read lock failed")] - UserDatabaseReadLocked = 3, + #[display(fmt = "Acquire database write lock failed")] + AcquireWriteLockedFailed = 2, + #[display(fmt = "Acquire database read lock failed")] + AcquireReadLockedFailed = 3, #[display(fmt = "Opening database is not belonging to the current user")] UserDatabaseDidNotMatch = 4, #[display(fmt = "Database internal error")] diff --git a/rust-lib/flowy-user/src/handlers/auth_handler.rs b/rust-lib/flowy-user/src/handlers/auth_handler.rs index 95f07b2ab6..9c52be4d5e 100644 --- a/rust-lib/flowy-user/src/handlers/auth_handler.rs +++ b/rust-lib/flowy-user/src/handlers/auth_handler.rs @@ -4,13 +4,9 @@ use std::{convert::TryInto, sync::Arc}; // tracing instrument 👉🏻 https://docs.rs/tracing/0.1.26/tracing/attr.instrument.html #[tracing::instrument(name = "sign_in", skip(data, session), fields(email = %data.email))] -pub async fn sign_in( - data: Data, - session: Unit>, -) -> DataResult { +pub async fn sign_in(data: Data, session: Unit>) -> DataResult { let params: SignInParams = data.into_inner().try_into()?; - let user = session.sign_in(params).await?; - let user_detail = UserDetail::from(user); + let user_detail = session.sign_in(params).await?; data_result(user_detail) } @@ -22,12 +18,9 @@ pub async fn sign_in( name = %data.name, ) )] -pub async fn sign_up( - data: Data, - session: Unit>, -) -> DataResult { +pub async fn sign_up(data: Data, session: Unit>) -> DataResult { let params: SignUpParams = data.into_inner().try_into()?; - let user = session.sign_up(params).await?; - let user_detail = UserDetail::from(user); + let user_detail = session.sign_up(params).await?; + data_result(user_detail) } diff --git a/rust-lib/flowy-user/src/protobuf/model/errors.rs b/rust-lib/flowy-user/src/protobuf/model/errors.rs index ba4ca0752a..8ad23094ed 100644 --- a/rust-lib/flowy-user/src/protobuf/model/errors.rs +++ b/rust-lib/flowy-user/src/protobuf/model/errors.rs @@ -217,8 +217,8 @@ impl ::protobuf::reflect::ProtobufValue for UserError { pub enum ErrorCode { Unknown = 0, UserDatabaseInitFailed = 1, - UserDatabaseWriteLocked = 2, - UserDatabaseReadLocked = 3, + AcquireWriteLockedFailed = 2, + AcquireReadLockedFailed = 3, UserDatabaseDidNotMatch = 4, UserDatabaseInternalError = 5, SqlInternalError = 6, @@ -253,8 +253,8 @@ impl ::protobuf::ProtobufEnum for ErrorCode { match value { 0 => ::std::option::Option::Some(ErrorCode::Unknown), 1 => ::std::option::Option::Some(ErrorCode::UserDatabaseInitFailed), - 2 => ::std::option::Option::Some(ErrorCode::UserDatabaseWriteLocked), - 3 => ::std::option::Option::Some(ErrorCode::UserDatabaseReadLocked), + 2 => ::std::option::Option::Some(ErrorCode::AcquireWriteLockedFailed), + 3 => ::std::option::Option::Some(ErrorCode::AcquireReadLockedFailed), 4 => ::std::option::Option::Some(ErrorCode::UserDatabaseDidNotMatch), 5 => ::std::option::Option::Some(ErrorCode::UserDatabaseInternalError), 6 => ::std::option::Option::Some(ErrorCode::SqlInternalError), @@ -286,8 +286,8 @@ impl ::protobuf::ProtobufEnum for ErrorCode { static values: &'static [ErrorCode] = &[ ErrorCode::Unknown, ErrorCode::UserDatabaseInitFailed, - ErrorCode::UserDatabaseWriteLocked, - ErrorCode::UserDatabaseReadLocked, + ErrorCode::AcquireWriteLockedFailed, + ErrorCode::AcquireReadLockedFailed, ErrorCode::UserDatabaseDidNotMatch, ErrorCode::UserDatabaseInternalError, ErrorCode::SqlInternalError, @@ -341,10 +341,10 @@ impl ::protobuf::reflect::ProtobufValue for ErrorCode { static file_descriptor_proto_data: &'static [u8] = b"\ \n\x0cerrors.proto\"=\n\tUserError\x12\x1e\n\x04code\x18\x01\x20\x01(\ \x0e2\n.ErrorCodeR\x04code\x12\x10\n\x03msg\x18\x02\x20\x01(\tR\x03msg*\ - \xb9\x05\n\tErrorCode\x12\x0b\n\x07Unknown\x10\0\x12\x1a\n\x16UserDataba\ - seInitFailed\x10\x01\x12\x1b\n\x17UserDatabaseWriteLocked\x10\x02\x12\ - \x1a\n\x16UserDatabaseReadLocked\x10\x03\x12\x1b\n\x17UserDatabaseDidNot\ - Match\x10\x04\x12\x1d\n\x19UserDatabaseInternalError\x10\x05\x12\x14\n\ + \xbb\x05\n\tErrorCode\x12\x0b\n\x07Unknown\x10\0\x12\x1a\n\x16UserDataba\ + seInitFailed\x10\x01\x12\x1c\n\x18AcquireWriteLockedFailed\x10\x02\x12\ + \x1b\n\x17AcquireReadLockedFailed\x10\x03\x12\x1b\n\x17UserDatabaseDidNo\ + tMatch\x10\x04\x12\x1d\n\x19UserDatabaseInternalError\x10\x05\x12\x14\n\ \x10SqlInternalError\x10\x06\x12\x18\n\x14DatabaseConnectError\x10\x07\ \x12\x13\n\x0fUserNotLoginYet\x10\n\x12\x17\n\x13ReadCurrentIdFailed\x10\ \x0b\x12\x18\n\x14WriteCurrentIdFailed\x10\x0c\x12\x10\n\x0cEmailIsEmpty\ @@ -369,10 +369,10 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \x04\x0b\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x07\x0e\x0f\n\x0b\n\x04\x05\ \0\x02\x01\x12\x03\x08\x04\x1f\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x08\ \x04\x1a\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x08\x1d\x1e\n\x0b\n\x04\ - \x05\0\x02\x02\x12\x03\t\x04\x20\n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\t\ - \x04\x1b\n\x0c\n\x05\x05\0\x02\x02\x02\x12\x03\t\x1e\x1f\n\x0b\n\x04\x05\ - \0\x02\x03\x12\x03\n\x04\x1f\n\x0c\n\x05\x05\0\x02\x03\x01\x12\x03\n\x04\ - \x1a\n\x0c\n\x05\x05\0\x02\x03\x02\x12\x03\n\x1d\x1e\n\x0b\n\x04\x05\0\ + \x05\0\x02\x02\x12\x03\t\x04!\n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\t\ + \x04\x1c\n\x0c\n\x05\x05\0\x02\x02\x02\x12\x03\t\x1f\x20\n\x0b\n\x04\x05\ + \0\x02\x03\x12\x03\n\x04\x20\n\x0c\n\x05\x05\0\x02\x03\x01\x12\x03\n\x04\ + \x1b\n\x0c\n\x05\x05\0\x02\x03\x02\x12\x03\n\x1e\x1f\n\x0b\n\x04\x05\0\ \x02\x04\x12\x03\x0b\x04\x20\n\x0c\n\x05\x05\0\x02\x04\x01\x12\x03\x0b\ \x04\x1b\n\x0c\n\x05\x05\0\x02\x04\x02\x12\x03\x0b\x1e\x1f\n\x0b\n\x04\ \x05\0\x02\x05\x12\x03\x0c\x04\"\n\x0c\n\x05\x05\0\x02\x05\x01\x12\x03\ diff --git a/rust-lib/flowy-user/src/protobuf/proto/errors.proto b/rust-lib/flowy-user/src/protobuf/proto/errors.proto index e1d8bd9c48..0013634949 100644 --- a/rust-lib/flowy-user/src/protobuf/proto/errors.proto +++ b/rust-lib/flowy-user/src/protobuf/proto/errors.proto @@ -7,8 +7,8 @@ message UserError { enum ErrorCode { Unknown = 0; UserDatabaseInitFailed = 1; - UserDatabaseWriteLocked = 2; - UserDatabaseReadLocked = 3; + AcquireWriteLockedFailed = 2; + AcquireReadLockedFailed = 3; UserDatabaseDidNotMatch = 4; UserDatabaseInternalError = 5; SqlInternalError = 6; diff --git a/rust-lib/flowy-user/src/services/server/server_api_mock.rs b/rust-lib/flowy-user/src/services/server/server_api_mock.rs index 5a5f326bae..aca5fe07ab 100644 --- a/rust-lib/flowy-user/src/services/server/server_api_mock.rs +++ b/rust-lib/flowy-user/src/services/server/server_api_mock.rs @@ -15,21 +15,22 @@ impl UserServerAPI for UserServerMock { let uid = uuid(); ResultFuture::new(async move { Ok(SignUpResponse { - user_id: uid, + user_id: uid.clone(), name: params.name, email: params.email, - token: "fake token".to_owned(), + token: uid, }) }) } fn sign_in(&self, params: SignInParams) -> ResultFuture { + let user_id = uuid(); ResultFuture::new(async { Ok(SignInResponse { - uid: uuid(), + uid: user_id.clone(), name: "fake name".to_owned(), email: params.email, - token: "fake token".to_string(), + token: user_id, }) }) } diff --git a/rust-lib/flowy-user/src/services/user/database.rs b/rust-lib/flowy-user/src/services/user/database.rs index a7719d1bd6..7b32fb8c92 100644 --- a/rust-lib/flowy-user/src/services/user/database.rs +++ b/rust-lib/flowy-user/src/services/user/database.rs @@ -3,12 +3,8 @@ use flowy_database::{DBConnection, Database}; use flowy_sqlite::ConnectionPool; use lazy_static::lazy_static; use once_cell::sync::Lazy; -use parking_lot::Mutex; -use std::{ - collections::HashMap, - sync::{Arc, RwLock}, -}; - +use parking_lot::{lock_api::RwLockReadGuard, Mutex, RawRwLock, RwLock}; +use std::{collections::HashMap, sync::Arc, time::Duration}; lazy_static! { static ref DB: RwLock> = RwLock::new(None); } @@ -18,46 +14,42 @@ pub(crate) struct UserDB { } impl UserDB { - pub(crate) fn new(db_dir: &str) -> Self { - Self { - db_dir: db_dir.to_owned(), - } - } + pub(crate) fn new(db_dir: &str) -> Self { Self { db_dir: db_dir.to_owned() } } fn open_user_db(&self, user_id: &str) -> Result<(), UserError> { if user_id.is_empty() { - return Err(ErrorBuilder::new(ErrorCode::UserDatabaseInitFailed) - .msg("user id is empty") - .build()); + return Err(ErrorBuilder::new(ErrorCode::UserDatabaseInitFailed).msg("user id is empty").build()); } + log::info!("open user db {}", user_id); let dir = format!("{}/{}", self.db_dir, user_id); let db = flowy_database::init(&dir).map_err(|e| { - log::error!("flowy_database::init failed, {:?}", e); - ErrorBuilder::new(ErrorCode::UserDatabaseInitFailed) - .error(e) - .build() + log::error!("init user db failed, {:?}, user_id: {}", e, user_id); + ErrorBuilder::new(ErrorCode::UserDatabaseInitFailed).error(e).build() })?; - let mut db_map = DB_MAP.write().map_err(|e| { - ErrorBuilder::new(ErrorCode::UserDatabaseWriteLocked) - .error(e) - .build() - })?; - - db_map.insert(user_id.to_owned(), db); - Ok(()) + match DB_MAP.try_write_for(Duration::from_millis(300)) { + None => Err(ErrorBuilder::new(ErrorCode::AcquireWriteLockedFailed) + .msg(format!("Open user db failed")) + .build()), + Some(mut write_guard) => { + write_guard.insert(user_id.to_owned(), db); + Ok(()) + }, + } } pub(crate) fn close_user_db(&self, user_id: &str) -> Result<(), UserError> { - let mut db_map = DB_MAP.write().map_err(|e| { - ErrorBuilder::new(ErrorCode::UserDatabaseWriteLocked) - .msg(format!("Close user db failed. {:?}", e)) - .build() - })?; - set_user_db_init(false, user_id); - db_map.remove(user_id); - Ok(()) + match DB_MAP.try_write_for(Duration::from_millis(300)) { + None => Err(ErrorBuilder::new(ErrorCode::AcquireWriteLockedFailed) + .msg(format!("Close user db failed")) + .build()), + Some(mut write_guard) => { + set_user_db_init(false, user_id); + write_guard.remove(user_id); + Ok(()) + }, + } } pub(crate) fn get_connection(&self, user_id: &str) -> Result { @@ -66,22 +58,28 @@ impl UserDB { } pub(crate) fn get_pool(&self, user_id: &str) -> Result, UserError> { - if !is_user_db_init(user_id) { - let _ = self.open_user_db(user_id)?; - set_user_db_init(true, user_id); + // Opti: INIT_LOCK try to lock the INIT_RECORD accesses. Because the write guard + // can not nested in the read guard that will cause the deadlock. + match INIT_LOCK.try_lock_for(Duration::from_millis(300)) { + None => log::error!("get_pool fail"), + Some(_) => { + if !is_user_db_init(user_id) { + let _ = self.open_user_db(user_id)?; + set_user_db_init(true, user_id); + } + }, } - let db_map = DB_MAP.read().map_err(|e| { - ErrorBuilder::new(ErrorCode::UserDatabaseReadLocked) - .error(e) - .build() - })?; - - match db_map.get(user_id) { - None => Err(ErrorBuilder::new(ErrorCode::UserDatabaseInitFailed) - .msg("Get connection failed. The database is not initialization") + match DB_MAP.try_read_for(Duration::from_millis(300)) { + None => Err(ErrorBuilder::new(ErrorCode::AcquireReadLockedFailed) + .msg(format!("Read user db failed")) .build()), - Some(database) => Ok(database.get_pool()), + Some(read_guard) => match read_guard.get(user_id) { + None => Err(ErrorBuilder::new(ErrorCode::UserDatabaseInitFailed) + .msg("Get connection failed. The database is not initialization") + .build()), + Some(database) => Ok(database.get_pool()), + }, } } } @@ -90,14 +88,15 @@ lazy_static! { static ref DB_MAP: RwLock> = RwLock::new(HashMap::new()); } -static INIT_FLAG_MAP: Lazy>> = Lazy::new(|| Mutex::new(HashMap::new())); +static INIT_LOCK: Lazy> = Lazy::new(|| Mutex::new(())); +static INIT_RECORD: Lazy>> = Lazy::new(|| Mutex::new(HashMap::new())); fn set_user_db_init(is_init: bool, user_id: &str) { - let mut flag_map = INIT_FLAG_MAP.lock(); - flag_map.insert(user_id.to_owned(), is_init); + let mut record = INIT_RECORD.lock(); + record.insert(user_id.to_owned(), is_init); } fn is_user_db_init(user_id: &str) -> bool { - match INIT_FLAG_MAP.lock().get(user_id) { + match INIT_RECORD.lock().get(user_id) { None => false, Some(flag) => flag.clone(), } diff --git a/rust-lib/flowy-user/src/services/user/user_session.rs b/rust-lib/flowy-user/src/services/user/user_session.rs index 5524f11428..bd5441f845 100644 --- a/rust-lib/flowy-user/src/services/user/user_session.rs +++ b/rust-lib/flowy-user/src/services/user/user_session.rs @@ -69,22 +69,36 @@ impl UserSession { self.database.get_pool(&user_id) } - pub async fn sign_in(&self, params: SignInParams) -> Result { - let resp = self.server.sign_in(params).await?; - let session = Session::new(&resp.uid, &resp.token); - let _ = self.set_session(Some(session))?; - let user_table = self.save_user(resp.into()).await?; - - Ok(user_table) + pub async fn sign_in(&self, params: SignInParams) -> Result { + if self.is_login(¶ms.email) { + self.user_detail().await + } else { + let resp = self.server.sign_in(params).await?; + let session = Session::new(&resp.uid, &resp.token, &resp.email); + let _ = self.set_session(Some(session))?; + let user_table = self.save_user(resp.into()).await?; + let user_detail = UserDetail::from(user_table); + Ok(user_detail) + } } - pub async fn sign_up(&self, params: SignUpParams) -> Result { + pub async fn sign_up(&self, params: SignUpParams) -> Result { + // if self.is_login(¶ms.email) { + // self.user_detail().await + // } else { + // let resp = self.server.sign_up(params).await?; + // let session = Session::new(&resp.user_id, &resp.token, &resp.email); + // let _ = self.set_session(Some(session))?; + // let user_table = self.save_user(resp.into()).await?; + // let user_detail = UserDetail::from(user_table); + // Ok(user_detail) + // } let resp = self.server.sign_up(params).await?; - let session = Session::new(&resp.user_id, &resp.token); + let session = Session::new(&resp.user_id, &resp.token, &resp.email); let _ = self.set_session(Some(session))?; let user_table = self.save_user(resp.into()).await?; - - Ok(user_table) + let user_detail = UserDetail::from(user_table); + Ok(user_detail) } pub async fn sign_out(&self) -> Result<(), UserError> { @@ -170,6 +184,7 @@ impl UserSession { *self.session.write() = session; Ok(()) } + fn get_session(&self) -> Result { let mut session = { (*self.session.read()).clone() }; if session.is_none() { @@ -187,6 +202,13 @@ impl UserSession { Some(session) => Ok(session), } } + + fn is_login(&self, email: &str) -> bool { + match self.get_session() { + Ok(session) => session.email == email, + Err(_) => false, + } + } } pub async fn update_user(_server: Server, pool: Arc, params: UpdateUserParams) -> Result<(), UserError> { @@ -213,13 +235,15 @@ const SESSION_CACHE_KEY: &str = "session_cache_key"; struct Session { user_id: String, token: String, + email: String, } impl Session { - pub fn new(user_id: &str, token: &str) -> Self { + pub fn new(user_id: &str, token: &str, email: &str) -> Self { Self { user_id: user_id.to_owned(), token: token.to_owned(), + email: email.to_owned(), } } } diff --git a/rust-lib/flowy-user/tests/event/auth_test.rs b/rust-lib/flowy-user/tests/event/auth_test.rs index 13034be9c7..8fd1696df4 100644 --- a/rust-lib/flowy-user/tests/event/auth_test.rs +++ b/rust-lib/flowy-user/tests/event/auth_test.rs @@ -1,11 +1,12 @@ use crate::helper::*; +use flowy_test::builder::UserTestBuilder; use flowy_user::{errors::ErrorCode, event::UserEvent::*, prelude::*}; use serial_test::*; #[test] #[serial] fn sign_up_success() { - let user_detail = TestBuilder::new().sign_up().user_detail; + let user_detail = UserTestBuilder::new().sign_up().user_detail; log::info!("{:?}", user_detail); } @@ -16,16 +17,11 @@ fn sign_up_with_invalid_email() { let request = SignUpRequest { email: email.to_string(), name: valid_name(), - password: valid_password(), + password: login_password(), }; assert_eq!( - TestBuilder::new() - .event(SignUp) - .request(request) - .sync_send() - .error() - .code, + UserTestBuilder::new().event(SignUp).request(request).sync_send().error().code, ErrorCode::EmailFormatInvalid ); } @@ -40,27 +36,23 @@ fn sign_up_with_invalid_password() { password, }; - TestBuilder::new() - .event(SignUp) - .request(request) - .sync_send() - .assert_error(); + UserTestBuilder::new().event(SignUp).request(request).sync_send().assert_error(); } } #[test] #[serial] fn sign_in_success() { - let context = TestBuilder::new().sign_up(); + let context = UserTestBuilder::new().sign_up(); - let _ = TestBuilder::new().event(SignOut).sync_send(); + let _ = UserTestBuilder::new().event(SignOut).sync_send(); let request = SignInRequest { email: context.user_detail.email, password: context.password, }; - let response = TestBuilder::new() + let response = UserTestBuilder::new() .event(SignIn) .request(request) .sync_send() @@ -74,16 +66,11 @@ fn sign_in_with_invalid_email() { for email in invalid_email_test_case() { let request = SignInRequest { email: email.to_string(), - password: valid_password(), + password: login_password(), }; assert_eq!( - TestBuilder::new() - .event(SignIn) - .request(request) - .sync_send() - .error() - .code, + UserTestBuilder::new().event(SignIn).request(request).sync_send().error().code, ErrorCode::EmailFormatInvalid ); } @@ -98,10 +85,6 @@ fn sign_in_with_invalid_password() { password, }; - TestBuilder::new() - .event(SignIn) - .request(request) - .sync_send() - .assert_error(); + UserTestBuilder::new().event(SignIn).request(request).sync_send().assert_error(); } } diff --git a/rust-lib/flowy-user/tests/event/helper.rs b/rust-lib/flowy-user/tests/event/helper.rs index 90e1a6d94d..2afc5b8a01 100644 --- a/rust-lib/flowy-user/tests/event/helper.rs +++ b/rust-lib/flowy-user/tests/event/helper.rs @@ -1,6 +1,7 @@ -pub use flowy_test::builder::TestBuilder; - -pub use flowy_test::prelude::{random_email, valid_password}; +pub use flowy_test::{ + builder::*, + prelude::{login_password, random_email}, +}; pub(crate) fn invalid_email_test_case() -> Vec { // https://gist.github.com/cjaoude/fd9910626629b53c4d25 diff --git a/rust-lib/flowy-user/tests/event/user_profile_test.rs b/rust-lib/flowy-user/tests/event/user_profile_test.rs index e90d16634a..c72d9bca5a 100644 --- a/rust-lib/flowy-user/tests/event/user_profile_test.rs +++ b/rust-lib/flowy-user/tests/event/user_profile_test.rs @@ -1,28 +1,22 @@ use crate::helper::*; use flowy_infra::uuid; +use flowy_test::builder::UserTestBuilder; use flowy_user::{errors::ErrorCode, event::UserEvent::*, prelude::*}; use serial_test::*; #[test] #[serial] fn user_status_get_failed() { - let user_detail = TestBuilder::new() - .event(GetUserProfile) - .assert_error() - .sync_send() - .user_detail; - assert!(user_detail.is_none()) + let tester = UserTestBuilder::new().event(GetUserProfile).assert_error().sync_send(); + assert!(tester.get_user_detail().is_none()) } #[test] #[serial] fn user_detail_get() { - let user_detail = TestBuilder::new().sign_up().user_detail; + let user_detail = UserTestBuilder::new().sign_up().user_detail; - let user_detail2 = TestBuilder::new() - .event(GetUserProfile) - .sync_send() - .parse::(); + let user_detail2 = UserTestBuilder::new().event(GetUserProfile).sync_send().parse::(); assert_eq!(user_detail, user_detail2); } @@ -30,15 +24,12 @@ fn user_detail_get() { #[test] #[serial] fn user_update_with_name() { - let user_detail = TestBuilder::new().sign_up().user_detail; + let user_detail = UserTestBuilder::new().sign_up().user_detail; let new_name = "hello_world".to_owned(); let request = UpdateUserRequest::new(&user_detail.id).name(&new_name); - let _ = TestBuilder::new() - .event(UpdateUser) - .request(request) - .sync_send(); + let _ = UserTestBuilder::new().event(UpdateUser).request(request).sync_send(); - let user_detail = TestBuilder::new() + let user_detail = UserTestBuilder::new() .event(GetUserProfile) .assert_error() .sync_send() @@ -50,16 +41,13 @@ fn user_update_with_name() { #[test] #[serial] fn user_update_with_email() { - let user_detail = TestBuilder::new().sign_up().user_detail; + let user_detail = UserTestBuilder::new().sign_up().user_detail; let new_email = format!("{}@gmai.com", uuid()); let request = UpdateUserRequest::new(&user_detail.id).email(&new_email); - let _ = TestBuilder::new() - .event(UpdateUser) - .request(request) - .sync_send(); + let _ = UserTestBuilder::new().event(UpdateUser).request(request).sync_send(); - let user_detail = TestBuilder::new() + let user_detail = UserTestBuilder::new() .event(GetUserProfile) .assert_error() .sync_send() @@ -71,11 +59,11 @@ fn user_update_with_email() { #[test] #[serial] fn user_update_with_password() { - let user_detail = TestBuilder::new().sign_up().user_detail; + let user_detail = UserTestBuilder::new().sign_up().user_detail; let new_password = "H123world!".to_owned(); let request = UpdateUserRequest::new(&user_detail.id).password(&new_password); - let _ = TestBuilder::new() + let _ = UserTestBuilder::new() .event(UpdateUser) .request(request) .sync_send() @@ -85,16 +73,11 @@ fn user_update_with_password() { #[test] #[serial] fn user_update_with_invalid_email() { - let user_detail = TestBuilder::new().sign_up().user_detail; + let user_detail = UserTestBuilder::new().sign_up().user_detail; for email in invalid_email_test_case() { let request = UpdateUserRequest::new(&user_detail.id).email(&email); assert_eq!( - TestBuilder::new() - .event(UpdateUser) - .request(request) - .sync_send() - .error() - .code, + UserTestBuilder::new().event(UpdateUser).request(request).sync_send().error().code, ErrorCode::EmailFormatInvalid ); } @@ -103,27 +86,19 @@ fn user_update_with_invalid_email() { #[test] #[serial] fn user_update_with_invalid_password() { - let user_detail = TestBuilder::new().sign_up().user_detail; + let user_detail = UserTestBuilder::new().sign_up().user_detail; for password in invalid_password_test_case() { let request = UpdateUserRequest::new(&user_detail.id).password(&password); - TestBuilder::new() - .event(UpdateUser) - .request(request) - .sync_send() - .assert_error(); + UserTestBuilder::new().event(UpdateUser).request(request).sync_send().assert_error(); } } #[test] #[serial] fn user_update_with_invalid_name() { - let user_detail = TestBuilder::new().sign_up().user_detail; + let user_detail = UserTestBuilder::new().sign_up().user_detail; let request = UpdateUserRequest::new(&user_detail.id).name(""); - TestBuilder::new() - .event(UpdateUser) - .request(request) - .sync_send() - .assert_error(); + UserTestBuilder::new().event(UpdateUser).request(request).sync_send().assert_error(); } diff --git a/rust-lib/flowy-workspace/tests/event/app_test.rs b/rust-lib/flowy-workspace/tests/event/app_test.rs index 5f1b6f1724..6cf711eae7 100644 --- a/rust-lib/flowy-workspace/tests/event/app_test.rs +++ b/rust-lib/flowy-workspace/tests/event/app_test.rs @@ -1,5 +1,6 @@ use crate::helper::*; +use flowy_test::builder::UserTestBuilder; use flowy_workspace::entities::{ app::{QueryAppRequest, UpdateAppRequest}, view::*, @@ -7,6 +8,7 @@ use flowy_workspace::entities::{ #[test] fn app_create() { + let _ = UserTestBuilder::new().sign_up(); let workspace = create_workspace("Workspace", ""); let app = create_app("App A", "AppFlowy Github Project", &workspace.id); dbg!(&app); @@ -15,6 +17,8 @@ fn app_create() { #[test] #[should_panic] fn app_delete() { + let _ = UserTestBuilder::new().sign_up(); + let workspace = create_workspace("Workspace", ""); let app = create_app("App A", "AppFlowy Github Project", &workspace.id); delete_app(&app.id); @@ -24,6 +28,8 @@ fn app_delete() { #[test] fn app_read() { + let _ = UserTestBuilder::new().sign_up(); + let workspace = create_workspace("Workspace", ""); let app = create_app("App A", "AppFlowy Github Project", &workspace.id); let query = QueryAppRequest::new(&app.id); @@ -33,6 +39,7 @@ fn app_read() { #[test] fn app_create_with_view() { + let _a = UserTestBuilder::new().sign_up(); let workspace = create_workspace("Workspace", ""); let app = create_app("App A", "AppFlowy Github Project", &workspace.id); let request_a = CreateViewRequest { @@ -63,6 +70,7 @@ fn app_create_with_view() { #[test] fn app_set_trash_flag() { + let _ = UserTestBuilder::new().sign_up(); let app_id = create_app_with_trash_flag(); let query = QueryAppRequest::new(&app_id).set_is_trash(true); let _ = read_app(query); @@ -71,6 +79,7 @@ fn app_set_trash_flag() { #[test] #[should_panic] fn app_set_trash_flag_2() { + let _ = UserTestBuilder::new().sign_up(); let app_id = create_app_with_trash_flag(); let query = QueryAppRequest::new(&app_id); let _ = read_app(query); diff --git a/rust-lib/flowy-workspace/tests/event/helper.rs b/rust-lib/flowy-workspace/tests/event/helper.rs index c4abf2f0b3..6f78719e0d 100644 --- a/rust-lib/flowy-workspace/tests/event/helper.rs +++ b/rust-lib/flowy-workspace/tests/event/helper.rs @@ -1,4 +1,4 @@ -pub use flowy_test::builder::AnnieTestBuilder; +use flowy_test::builder::{UserTestBuilder, WorkspaceTestBuilder}; use flowy_workspace::{ entities::{app::*, view::*, workspace::*}, event::WorkspaceEvent::*, @@ -17,7 +17,7 @@ pub fn create_workspace(name: &str, desc: &str) -> Workspace { desc: desc.to_owned(), }; - let workspace = AnnieTestBuilder::new() + let workspace = WorkspaceTestBuilder::new() .event(CreateWorkspace) .request(request) .sync_send() @@ -26,13 +26,13 @@ pub fn create_workspace(name: &str, desc: &str) -> Workspace { } pub fn read_workspaces(request: QueryWorkspaceRequest) -> Option { - let mut repeated_workspace = AnnieTestBuilder::new() + let mut repeated_workspace = WorkspaceTestBuilder::new() .event(ReadWorkspaces) .request(request) .sync_send() .parse::(); - debug_assert_eq!(repeated_workspace.len(), 1); + debug_assert_eq!(repeated_workspace.len(), 1, "Default workspace not found"); repeated_workspace.drain(..1).collect::>().pop() } @@ -44,7 +44,7 @@ pub fn create_app(name: &str, desc: &str, workspace_id: &str) -> App { color_style: Default::default(), }; - let app = AnnieTestBuilder::new() + let app = WorkspaceTestBuilder::new() .event(CreateApp) .request(create_app_request) .sync_send() @@ -57,19 +57,23 @@ pub fn delete_app(app_id: &str) { app_id: app_id.to_string(), }; - AnnieTestBuilder::new().event(DeleteApp).request(delete_app_request).sync_send(); + WorkspaceTestBuilder::new().event(DeleteApp).request(delete_app_request).sync_send(); } -pub fn update_app(request: UpdateAppRequest) { AnnieTestBuilder::new().event(UpdateApp).request(request).sync_send(); } +pub fn update_app(request: UpdateAppRequest) { WorkspaceTestBuilder::new().event(UpdateApp).request(request).sync_send(); } pub fn read_app(request: QueryAppRequest) -> App { - let app = AnnieTestBuilder::new().event(ReadApp).request(request).sync_send().parse::(); + let app = WorkspaceTestBuilder::new() + .event(ReadApp) + .request(request) + .sync_send() + .parse::(); app } pub fn create_view_with_request(request: CreateViewRequest) -> View { - let view = AnnieTestBuilder::new() + let view = WorkspaceTestBuilder::new() .event(CreateView) .request(request) .sync_send() @@ -78,9 +82,8 @@ pub fn create_view_with_request(request: CreateViewRequest) -> View { view } -pub fn create_view() -> View { - let workspace = create_workspace("Workspace", ""); - let app = create_app("App A", "AppFlowy Github Project", &workspace.id); +pub fn create_view(workspace_id: &str) -> View { + let app = create_app("App A", "AppFlowy Github Project", workspace_id); let request = CreateViewRequest { belong_to_id: app.id.clone(), name: "View A".to_string(), @@ -92,6 +95,12 @@ pub fn create_view() -> View { create_view_with_request(request) } -pub fn update_view(request: UpdateViewRequest) { AnnieTestBuilder::new().event(UpdateView).request(request).sync_send(); } +pub fn update_view(request: UpdateViewRequest) { WorkspaceTestBuilder::new().event(UpdateView).request(request).sync_send(); } -pub fn read_view(request: QueryViewRequest) -> View { AnnieTestBuilder::new().event(ReadView).request(request).sync_send().parse::() } +pub fn read_view(request: QueryViewRequest) -> View { + WorkspaceTestBuilder::new() + .event(ReadView) + .request(request) + .sync_send() + .parse::() +} diff --git a/rust-lib/flowy-workspace/tests/event/view_test.rs b/rust-lib/flowy-workspace/tests/event/view_test.rs index 050b7ea3df..1a688629d2 100644 --- a/rust-lib/flowy-workspace/tests/event/view_test.rs +++ b/rust-lib/flowy-workspace/tests/event/view_test.rs @@ -1,12 +1,19 @@ use crate::helper::*; +use flowy_test::builder::UserTestBuilder; use flowy_workspace::entities::view::*; #[test] -fn view_create() { let _ = create_view(); } +fn view_create() { + let _ = UserTestBuilder::new().sign_up(); + + let workspace = create_workspace("Workspace", ""); + let _ = create_view(&workspace.id); +} #[test] fn view_set_trash_flag() { + let _ = UserTestBuilder::new().sign_up(); let view_id = create_view_with_trash_flag(); let query = QueryViewRequest::new(&view_id).set_is_trash(true); let _ = read_view(query); @@ -15,13 +22,16 @@ fn view_set_trash_flag() { #[test] #[should_panic] fn view_set_trash_flag2() { + let _ = UserTestBuilder::new().sign_up(); + let view_id = create_view_with_trash_flag(); let query = QueryViewRequest::new(&view_id); let _ = read_view(query); } fn create_view_with_trash_flag() -> String { - let view = create_view(); + let workspace = create_workspace("Workspace", ""); + let view = create_view(&workspace.id); let request = UpdateViewRequest { view_id: view.id.clone(), name: None, diff --git a/rust-lib/flowy-workspace/tests/event/workspace_test.rs b/rust-lib/flowy-workspace/tests/event/workspace_test.rs index 343ca11208..67849413b7 100644 --- a/rust-lib/flowy-workspace/tests/event/workspace_test.rs +++ b/rust-lib/flowy-workspace/tests/event/workspace_test.rs @@ -1,4 +1,5 @@ use crate::helper::*; +use flowy_test::builder::*; use flowy_workspace::{ entities::workspace::{CreateWorkspaceRequest, QueryWorkspaceRequest, RepeatedWorkspace}, event::WorkspaceEvent::*, @@ -10,11 +11,12 @@ fn workspace_create_success() { let _ = create_workspace("First workspace", ""); #[test] fn workspace_read_all() { + let _ = UserTestBuilder::new().sign_up(); let _ = create_workspace("Workspace A", "workspace_create_and_then_get_workspace_success"); - let request = QueryWorkspaceRequest::new(); - let workspaces = AnnieTestBuilder::new() + + let workspaces = WorkspaceTestBuilder::new() .event(ReadWorkspaces) - .request(request) + .request(QueryWorkspaceRequest::new()) .sync_send() .parse::(); @@ -42,11 +44,15 @@ fn workspace_create_with_apps() { #[test] fn workspace_create_with_invalid_name() { for name in invalid_workspace_name_test_case() { - let builder = AnnieTestBuilder::new(); + let _ = UserTestBuilder::new().sign_up(); let request = CreateWorkspaceRequest { name, desc: "".to_owned() }; - assert_eq!( - builder.event(CreateWorkspace).request(request).sync_send().error().code, + WorkspaceTestBuilder::new() + .event(CreateWorkspace) + .request(request) + .sync_send() + .error() + .code, ErrorCode::WorkspaceNameInvalid ) } @@ -54,12 +60,16 @@ fn workspace_create_with_invalid_name() { #[test] fn workspace_update_with_invalid_name() { + let _ = UserTestBuilder::new().sign_up(); for name in invalid_workspace_name_test_case() { - let builder = AnnieTestBuilder::new(); let request = CreateWorkspaceRequest { name, desc: "".to_owned() }; - assert_eq!( - builder.event(CreateWorkspace).request(request).sync_send().error().code, + WorkspaceTestBuilder::new() + .event(CreateWorkspace) + .request(request) + .sync_send() + .error() + .code, ErrorCode::WorkspaceNameInvalid ) }