mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix multithread test issue of database init
This commit is contained in:
@ -12,8 +12,8 @@ import 'package:protobuf/protobuf.dart' as $pb;
|
|||||||
class ErrorCode extends $pb.ProtobufEnum {
|
class ErrorCode extends $pb.ProtobufEnum {
|
||||||
static const ErrorCode Unknown = ErrorCode._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Unknown');
|
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 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 AcquireWriteLockedFailed = ErrorCode._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'AcquireWriteLockedFailed');
|
||||||
static const ErrorCode UserDatabaseReadLocked = ErrorCode._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserDatabaseReadLocked');
|
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 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 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');
|
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<ErrorCode> values = <ErrorCode> [
|
static const $core.List<ErrorCode> values = <ErrorCode> [
|
||||||
Unknown,
|
Unknown,
|
||||||
UserDatabaseInitFailed,
|
UserDatabaseInitFailed,
|
||||||
UserDatabaseWriteLocked,
|
AcquireWriteLockedFailed,
|
||||||
UserDatabaseReadLocked,
|
AcquireReadLockedFailed,
|
||||||
UserDatabaseDidNotMatch,
|
UserDatabaseDidNotMatch,
|
||||||
UserDatabaseInternalError,
|
UserDatabaseInternalError,
|
||||||
SqlInternalError,
|
SqlInternalError,
|
||||||
|
@ -14,8 +14,8 @@ const ErrorCode$json = const {
|
|||||||
'2': const [
|
'2': const [
|
||||||
const {'1': 'Unknown', '2': 0},
|
const {'1': 'Unknown', '2': 0},
|
||||||
const {'1': 'UserDatabaseInitFailed', '2': 1},
|
const {'1': 'UserDatabaseInitFailed', '2': 1},
|
||||||
const {'1': 'UserDatabaseWriteLocked', '2': 2},
|
const {'1': 'AcquireWriteLockedFailed', '2': 2},
|
||||||
const {'1': 'UserDatabaseReadLocked', '2': 3},
|
const {'1': 'AcquireReadLockedFailed', '2': 3},
|
||||||
const {'1': 'UserDatabaseDidNotMatch', '2': 4},
|
const {'1': 'UserDatabaseDidNotMatch', '2': 4},
|
||||||
const {'1': 'UserDatabaseInternalError', '2': 5},
|
const {'1': 'UserDatabaseInternalError', '2': 5},
|
||||||
const {'1': 'SqlInternalError', '2': 6},
|
const {'1': 'SqlInternalError', '2': 6},
|
||||||
@ -43,7 +43,7 @@ const ErrorCode$json = const {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Descriptor for `ErrorCode`. Decode as a `google.protobuf.EnumDescriptorProto`.
|
/// 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')
|
@$core.Deprecated('Use userErrorDescriptor instead')
|
||||||
const UserError$json = const {
|
const UserError$json = const {
|
||||||
'1': 'UserError',
|
'1': 'UserError',
|
||||||
|
@ -24,6 +24,7 @@ dyn-clone = "1.0"
|
|||||||
derivative = "2.2.0"
|
derivative = "2.2.0"
|
||||||
serde_json = {version = "1.0"}
|
serde_json = {version = "1.0"}
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
dashmap = "4.0"
|
||||||
|
|
||||||
#optional crate
|
#optional crate
|
||||||
bincode = { version = "1.3", optional = true}
|
bincode = { version = "1.3", optional = true}
|
||||||
|
@ -14,7 +14,7 @@ use std::{future::Future, sync::RwLock};
|
|||||||
use tokio::macros::support::{Pin, Poll};
|
use tokio::macros::support::{Pin, Poll};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref EVENT_DISPATCH: RwLock<Option<EventDispatch>> = RwLock::new(None);
|
static ref EVENT_DISPATCH: RwLock<Option<EventDispatch>> = RwLock::new(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EventDispatch {
|
pub struct EventDispatch {
|
||||||
@ -31,10 +31,7 @@ impl EventDispatch {
|
|||||||
log::trace!("{}", module_info(&modules));
|
log::trace!("{}", module_info(&modules));
|
||||||
let module_map = as_module_map(modules);
|
let module_map = as_module_map(modules);
|
||||||
let runtime = tokio_default_runtime().unwrap();
|
let runtime = tokio_default_runtime().unwrap();
|
||||||
let dispatch = EventDispatch {
|
let dispatch = EventDispatch { module_map, runtime };
|
||||||
module_map,
|
|
||||||
runtime,
|
|
||||||
};
|
|
||||||
*(EVENT_DISPATCH.write().unwrap()) = Some(dispatch);
|
*(EVENT_DISPATCH.write().unwrap()) = Some(dispatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,10 +42,7 @@ impl EventDispatch {
|
|||||||
EventDispatch::async_send_with_callback(request, |_| Box::pin(async {}))
|
EventDispatch::async_send_with_callback(request, |_| Box::pin(async {}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn async_send_with_callback<Req, Callback>(
|
pub fn async_send_with_callback<Req, Callback>(request: Req, callback: Callback) -> DispatchFuture<EventResponse>
|
||||||
request: Req,
|
|
||||||
callback: Callback,
|
|
||||||
) -> DispatchFuture<EventResponse>
|
|
||||||
where
|
where
|
||||||
Req: std::convert::Into<ModuleRequest>,
|
Req: std::convert::Into<ModuleRequest>,
|
||||||
Callback: FnOnce(EventResponse) -> BoxFuture<'static, ()> + 'static + Send + Sync,
|
Callback: FnOnce(EventResponse) -> BoxFuture<'static, ()> + 'static + Send + Sync,
|
||||||
@ -74,10 +68,7 @@ impl EventDispatch {
|
|||||||
DispatchFuture {
|
DispatchFuture {
|
||||||
fut: Box::pin(async move {
|
fut: Box::pin(async move {
|
||||||
join_handle.await.unwrap_or_else(|e| {
|
join_handle.await.unwrap_or_else(|e| {
|
||||||
let error = InternalError::JoinError(format!(
|
let error = InternalError::JoinError(format!("EVENT_DISPATCH join error: {:?}", e));
|
||||||
"EVENT_DISPATCH join error: {:?}",
|
|
||||||
e
|
|
||||||
));
|
|
||||||
error.as_response()
|
error.as_response()
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
@ -94,9 +85,7 @@ impl EventDispatch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn sync_send(request: ModuleRequest) -> EventResponse {
|
pub fn sync_send(request: ModuleRequest) -> EventResponse {
|
||||||
futures::executor::block_on(async {
|
futures::executor::block_on(async { EventDispatch::async_send_with_callback(request, |_| Box::pin(async {})).await })
|
||||||
EventDispatch::async_send_with_callback(request, |_| Box::pin(async {})).await
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,8 +109,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type BoxFutureCallback =
|
pub type BoxFutureCallback = Box<dyn FnOnce(EventResponse) -> BoxFuture<'static, ()> + 'static + Send + Sync>;
|
||||||
Box<dyn FnOnce(EventResponse) -> BoxFuture<'static, ()> + 'static + Send + Sync>;
|
|
||||||
|
|
||||||
#[derive(Derivative)]
|
#[derive(Derivative)]
|
||||||
#[derivative(Debug)]
|
#[derivative(Debug)]
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use crate::helper::*;
|
use crate::helper::*;
|
||||||
|
use flowy_test::builder::{TestBuilder, UserTestBuilder};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn file_create_test() {
|
fn file_create_test() {
|
||||||
|
let _ = UserTestBuilder::new().sign_up();
|
||||||
let doc_desc = create_doc("hello world", "flutter ❤️ rust", "123");
|
let doc_desc = create_doc("hello world", "flutter ❤️ rust", "123");
|
||||||
dbg!(&doc_desc);
|
dbg!(&doc_desc);
|
||||||
|
|
||||||
@ -11,6 +13,7 @@ fn file_create_test() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn file_update_text_test() {
|
fn file_update_text_test() {
|
||||||
|
let _ = UserTestBuilder::new().sign_up();
|
||||||
let doc_desc = create_doc("hello world", "flutter ❤️ rust", "");
|
let doc_desc = create_doc("hello world", "flutter ❤️ rust", "");
|
||||||
dbg!(&doc_desc);
|
dbg!(&doc_desc);
|
||||||
|
|
||||||
|
@ -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_document::{entities::doc::*, event::EditorEvent::*};
|
||||||
use flowy_infra::uuid;
|
use flowy_infra::uuid;
|
||||||
@ -11,13 +11,12 @@ pub fn create_doc(name: &str, desc: &str, text: &str) -> DocInfo {
|
|||||||
text: text.to_owned(),
|
text: text.to_owned(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let doc_desc = AnnieTestBuilder::new()
|
let doc = DocTestBuilder::new()
|
||||||
.event(CreateDoc)
|
.event(CreateDoc)
|
||||||
.request(request)
|
.request(request)
|
||||||
.sync_send()
|
.sync_send()
|
||||||
.parse::<DocInfo>();
|
.parse::<DocInfo>();
|
||||||
|
doc
|
||||||
doc_desc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_doc(desc: &DocInfo, content: &str) {
|
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()),
|
text: Some(content.to_owned()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = AnnieTestBuilder::new()
|
let _ = DocTestBuilder::new().event(UpdateDoc).request(request).sync_send();
|
||||||
.event(UpdateDoc)
|
|
||||||
.request(request)
|
|
||||||
.sync_send();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
// #[allow(dead_code)]
|
||||||
pub fn read_doc(doc_id: &str) -> DocInfo {
|
// pub fn read_doc(doc_id: &str) -> DocInfo {
|
||||||
let request = QueryDocRequest {
|
// let request = QueryDocRequest {
|
||||||
doc_id: doc_id.to_string(),
|
// doc_id: doc_id.to_string(),
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
|
// let doc = AnnieTestBuilder::new()
|
||||||
|
// .event(ReadDocInfo)
|
||||||
|
// .request(request)
|
||||||
|
// .sync_send()
|
||||||
|
// .parse::<DocInfo>();
|
||||||
|
//
|
||||||
|
// doc
|
||||||
|
// }
|
||||||
|
|
||||||
let doc = AnnieTestBuilder::new()
|
pub(crate) fn read_doc_data(doc_id: &str, path: &str) -> DocData {
|
||||||
.event(ReadDocInfo)
|
|
||||||
.request(request)
|
|
||||||
.sync_send()
|
|
||||||
.parse::<DocInfo>();
|
|
||||||
|
|
||||||
doc
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_doc_data(doc_id: &str, path: &str) -> DocData {
|
|
||||||
let request = QueryDocDataRequest {
|
let request = QueryDocDataRequest {
|
||||||
doc_id: doc_id.to_string(),
|
doc_id: doc_id.to_string(),
|
||||||
path: path.to_string(),
|
path: path.to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let doc = AnnieTestBuilder::new()
|
let doc = DocTestBuilder::new()
|
||||||
.event(ReadDocData)
|
.event(ReadDocData)
|
||||||
.request(request)
|
.request(request)
|
||||||
.sync_send()
|
.sync_send()
|
||||||
|
@ -11,6 +11,7 @@ flowy-dispatch = { path = "../flowy-dispatch"}
|
|||||||
flowy-user = { path = "../flowy-user"}
|
flowy-user = { path = "../flowy-user"}
|
||||||
flowy-workspace = { path = "../flowy-workspace"}
|
flowy-workspace = { path = "../flowy-workspace"}
|
||||||
flowy-infra = { path = "../flowy-infra"}
|
flowy-infra = { path = "../flowy-infra"}
|
||||||
|
flowy-document = { path = "../flowy-document"}
|
||||||
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
bincode = { version = "1.3"}
|
bincode = { version = "1.3"}
|
||||||
|
@ -6,45 +6,32 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
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},
|
tester::{TesterContext, TesterTrait},
|
||||||
};
|
};
|
||||||
|
use flowy_document::errors::DocError;
|
||||||
use flowy_user::errors::UserError;
|
use flowy_user::errors::UserError;
|
||||||
use flowy_workspace::errors::WorkspaceError;
|
use flowy_workspace::errors::WorkspaceError;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
pub type AnnieTestBuilder = Builder<FlowyAnnie<WorkspaceError>>;
|
pub type WorkspaceTestBuilder = Builder<RandomUserTester<WorkspaceError>>;
|
||||||
impl AnnieTestBuilder {
|
impl WorkspaceTestBuilder {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self { Builder::test(Box::new(RandomUserTester::<WorkspaceError>::new())) }
|
||||||
let mut builder = Builder::test(Box::new(FlowyAnnie::<WorkspaceError>::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 TestBuilder = Builder<RandomUserTester<UserError>>;
|
|
||||||
impl TestBuilder {
|
pub type DocTestBuilder = Builder<RandomUserTester<DocError>>;
|
||||||
|
impl DocTestBuilder {
|
||||||
|
pub fn new() -> Self { Builder::test(Box::new(RandomUserTester::<DocError>::new())) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type UserTestBuilder = Builder<RandomUserTester<UserError>>;
|
||||||
|
impl UserTestBuilder {
|
||||||
pub fn new() -> Self { Builder::test(Box::new(RandomUserTester::<UserError>::new())) }
|
pub fn new() -> Self { Builder::test(Box::new(RandomUserTester::<UserError>::new())) }
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Builder<T: TesterTrait> {
|
pub fn sign_up(mut self) -> SignUpContext {
|
||||||
pub tester: Box<T>,
|
|
||||||
pub user_detail: Option<UserDetail>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Builder<T>
|
|
||||||
where
|
|
||||||
T: TesterTrait,
|
|
||||||
{
|
|
||||||
fn test(tester: Box<T>) -> Self { Self { tester, user_detail: None } }
|
|
||||||
|
|
||||||
pub fn sign_up(self) -> SignUpContext {
|
|
||||||
let (user_detail, password) = self.tester.sign_up();
|
let (user_detail, password) = self.tester.sign_up();
|
||||||
|
let _ = create_default_workspace_if_need(&user_detail.id);
|
||||||
SignUpContext { user_detail, password }
|
SignUpContext { user_detail, password }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,6 +46,23 @@ where
|
|||||||
self.user_detail = Some(user_detail);
|
self.user_detail = Some(user_detail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_user_detail(&self) -> &Option<UserDetail> { &self.user_detail }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Builder<T: TesterTrait> {
|
||||||
|
pub tester: Box<T>,
|
||||||
|
user_detail: Option<UserDetail>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Builder<T>
|
||||||
|
where
|
||||||
|
T: TesterTrait,
|
||||||
|
{
|
||||||
|
fn test(tester: Box<T>) -> Self {
|
||||||
|
init_test_sdk();
|
||||||
|
Self { tester, user_detail: None }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn request<P>(mut self, request: P) -> Self
|
pub fn request<P>(mut self, request: P) -> Self
|
||||||
where
|
where
|
||||||
P: ToBytes,
|
P: ToBytes,
|
||||||
@ -128,34 +132,6 @@ where
|
|||||||
fn context(&self) -> &TesterContext { &self.context }
|
fn context(&self) -> &TesterContext { &self.context }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FlowyAnnie<Error> {
|
|
||||||
context: TesterContext,
|
|
||||||
err_phantom: PhantomData<Error>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Error> FlowyAnnie<Error>
|
|
||||||
where
|
|
||||||
Error: FromBytes + Debug,
|
|
||||||
{
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
context: TesterContext::new(valid_email()),
|
|
||||||
err_phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Error> TesterTrait for FlowyAnnie<Error>
|
|
||||||
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 struct SignUpContext {
|
||||||
pub user_detail: UserDetail,
|
pub user_detail: UserDetail,
|
||||||
pub password: String,
|
pub password: String,
|
||||||
|
@ -4,6 +4,7 @@ use flowy_infra::{kv::KV, uuid};
|
|||||||
use flowy_user::errors::{ErrorBuilder, ErrorCode, UserError};
|
use flowy_user::errors::{ErrorBuilder, ErrorCode, UserError};
|
||||||
use flowy_workspace::{
|
use flowy_workspace::{
|
||||||
entities::workspace::{CreateWorkspaceRequest, QueryWorkspaceRequest, Workspace},
|
entities::workspace::{CreateWorkspaceRequest, QueryWorkspaceRequest, Workspace},
|
||||||
|
errors::WorkspaceError,
|
||||||
event::WorkspaceEvent::{CreateWorkspace, OpenWorkspace},
|
event::WorkspaceEvent::{CreateWorkspace, OpenWorkspace},
|
||||||
};
|
};
|
||||||
use std::{fs, path::PathBuf};
|
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 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_NAME: &'static str = "My workspace";
|
||||||
const DEFAULT_WORKSPACE_DESC: &'static str = "This is your first 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 request = ModuleRequest::new(CreateWorkspace).payload(payload);
|
||||||
let result = EventDispatch::sync_send(request)
|
let result = EventDispatch::sync_send(request)
|
||||||
.parse::<Workspace, DispatchError>()
|
.parse::<Workspace, WorkspaceError>()
|
||||||
.map_err(|e| ErrorBuilder::new(ErrorCode::CreateDefaultWorkspaceFailed).error(e).build())?;
|
.map_err(|e| ErrorBuilder::new(ErrorCode::CreateDefaultWorkspaceFailed).error(e).build())?;
|
||||||
|
|
||||||
let workspace = result.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 request = ModuleRequest::new(OpenWorkspace).payload(query);
|
||||||
let _result = EventDispatch::sync_send(request)
|
let _result = EventDispatch::sync_send(request)
|
||||||
.parse::<Workspace, DispatchError>()
|
.parse::<Workspace, WorkspaceError>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -7,10 +7,7 @@ use flowy_sdk::FlowySDK;
|
|||||||
use std::sync::Once;
|
use std::sync::Once;
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::{
|
pub use crate::{builder::*, helper::*};
|
||||||
builder::{TestBuilder, *},
|
|
||||||
helper::*,
|
|
||||||
};
|
|
||||||
pub use flowy_dispatch::prelude::*;
|
pub use flowy_dispatch::prelude::*;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
helper::{random_email, valid_password},
|
helper::{login_password, random_email},
|
||||||
init_test_sdk,
|
init_test_sdk,
|
||||||
};
|
};
|
||||||
use flowy_dispatch::prelude::*;
|
use flowy_dispatch::prelude::*;
|
||||||
@ -10,6 +10,7 @@ use flowy_user::{
|
|||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::helper::login_email;
|
||||||
use flowy_user::event::UserEvent::SignIn;
|
use flowy_user::event::UserEvent::SignIn;
|
||||||
use std::{
|
use std::{
|
||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
@ -22,15 +23,10 @@ pub struct TesterContext {
|
|||||||
request: Option<ModuleRequest>,
|
request: Option<ModuleRequest>,
|
||||||
response: Option<EventResponse>,
|
response: Option<EventResponse>,
|
||||||
status_code: StatusCode,
|
status_code: StatusCode,
|
||||||
user_email: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TesterContext {
|
impl TesterContext {
|
||||||
pub fn new(email: String) -> Self {
|
pub fn new(email: String) -> Self { TesterContext::default() }
|
||||||
let mut ctx = TesterContext::default();
|
|
||||||
ctx.user_email = email;
|
|
||||||
ctx
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::default::Default for TesterContext {
|
impl std::default::Default for TesterContext {
|
||||||
@ -39,7 +35,6 @@ impl std::default::Default for TesterContext {
|
|||||||
request: None,
|
request: None,
|
||||||
status_code: StatusCode::Ok,
|
status_code: StatusCode::Ok,
|
||||||
response: None,
|
response: None,
|
||||||
user_email: random_email(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,7 +54,6 @@ pub trait TesterTrait {
|
|||||||
where
|
where
|
||||||
E: Eq + Hash + Debug + Clone + Display,
|
E: Eq + Hash + Debug + Clone + Display,
|
||||||
{
|
{
|
||||||
init_test_sdk();
|
|
||||||
self.mut_context().request = Some(ModuleRequest::new(event));
|
self.mut_context().request = Some(ModuleRequest::new(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,16 +95,13 @@ pub trait TesterTrait {
|
|||||||
fn error(&mut self) -> Self::Error {
|
fn error(&mut self) -> Self::Error {
|
||||||
let response = self.mut_context().response.clone().unwrap();
|
let response = self.mut_context().response.clone().unwrap();
|
||||||
assert_eq!(response.status_code, StatusCode::Err);
|
assert_eq!(response.status_code, StatusCode::Err);
|
||||||
<Data<Self::Error>>::try_from(response.payload)
|
<Data<Self::Error>>::try_from(response.payload).unwrap().into_inner()
|
||||||
.unwrap()
|
|
||||||
.into_inner()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_up(&self) -> (UserDetail, String) {
|
fn sign_up(&self) -> (UserDetail, String) {
|
||||||
init_test_sdk();
|
let password = login_password();
|
||||||
let password = valid_password();
|
|
||||||
let payload = SignUpRequest {
|
let payload = SignUpRequest {
|
||||||
email: self.context().user_email.clone(),
|
email: random_email(),
|
||||||
name: "app flowy".to_string(),
|
name: "app flowy".to_string(),
|
||||||
password: password.clone(),
|
password: password.clone(),
|
||||||
}
|
}
|
||||||
@ -118,34 +109,26 @@ pub trait TesterTrait {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let request = ModuleRequest::new(SignUp).payload(payload);
|
let request = ModuleRequest::new(SignUp).payload(payload);
|
||||||
let user_detail = EventDispatch::sync_send(request)
|
let user_detail = EventDispatch::sync_send(request).parse::<UserDetail, UserError>().unwrap().unwrap();
|
||||||
.parse::<UserDetail, UserError>()
|
|
||||||
.unwrap()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
(user_detail, password)
|
(user_detail, password)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_in(&self) -> UserDetail {
|
fn sign_in(&self) -> UserDetail {
|
||||||
init_test_sdk();
|
|
||||||
let payload = SignInRequest {
|
let payload = SignInRequest {
|
||||||
email: self.context().user_email.clone(),
|
email: login_email(),
|
||||||
password: valid_password(),
|
password: login_password(),
|
||||||
}
|
}
|
||||||
.into_bytes()
|
.into_bytes()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let request = ModuleRequest::new(SignIn).payload(payload);
|
let request = ModuleRequest::new(SignIn).payload(payload);
|
||||||
let user_detail = EventDispatch::sync_send(request)
|
let user_detail = EventDispatch::sync_send(request).parse::<UserDetail, UserError>().unwrap().unwrap();
|
||||||
.parse::<UserDetail, UserError>()
|
|
||||||
.unwrap()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
user_detail
|
user_detail
|
||||||
}
|
}
|
||||||
|
|
||||||
fn login_if_need(&self) -> UserDetail {
|
fn login_if_need(&self) -> UserDetail {
|
||||||
init_test_sdk();
|
|
||||||
match EventDispatch::sync_send(ModuleRequest::new(GetUserProfile))
|
match EventDispatch::sync_send(ModuleRequest::new(GetUserProfile))
|
||||||
.parse::<UserDetail, UserError>()
|
.parse::<UserDetail, UserError>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -155,8 +138,5 @@ pub trait TesterTrait {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn logout(&self) {
|
fn logout(&self) { let _ = EventDispatch::sync_send(ModuleRequest::new(SignOut)); }
|
||||||
init_test_sdk();
|
|
||||||
let _ = EventDispatch::sync_send(ModuleRequest::new(SignOut));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -27,10 +27,10 @@ pub enum ErrorCode {
|
|||||||
Unknown = 0,
|
Unknown = 0,
|
||||||
#[display(fmt = "Database init failed")]
|
#[display(fmt = "Database init failed")]
|
||||||
UserDatabaseInitFailed = 1,
|
UserDatabaseInitFailed = 1,
|
||||||
#[display(fmt = "Get database write lock failed")]
|
#[display(fmt = "Acquire database write lock failed")]
|
||||||
UserDatabaseWriteLocked = 2,
|
AcquireWriteLockedFailed = 2,
|
||||||
#[display(fmt = "Get database read lock failed")]
|
#[display(fmt = "Acquire database read lock failed")]
|
||||||
UserDatabaseReadLocked = 3,
|
AcquireReadLockedFailed = 3,
|
||||||
#[display(fmt = "Opening database is not belonging to the current user")]
|
#[display(fmt = "Opening database is not belonging to the current user")]
|
||||||
UserDatabaseDidNotMatch = 4,
|
UserDatabaseDidNotMatch = 4,
|
||||||
#[display(fmt = "Database internal error")]
|
#[display(fmt = "Database internal error")]
|
||||||
|
@ -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 👉🏻 https://docs.rs/tracing/0.1.26/tracing/attr.instrument.html
|
||||||
#[tracing::instrument(name = "sign_in", skip(data, session), fields(email = %data.email))]
|
#[tracing::instrument(name = "sign_in", skip(data, session), fields(email = %data.email))]
|
||||||
pub async fn sign_in(
|
pub async fn sign_in(data: Data<SignInRequest>, session: Unit<Arc<UserSession>>) -> DataResult<UserDetail, UserError> {
|
||||||
data: Data<SignInRequest>,
|
|
||||||
session: Unit<Arc<UserSession>>,
|
|
||||||
) -> DataResult<UserDetail, UserError> {
|
|
||||||
let params: SignInParams = data.into_inner().try_into()?;
|
let params: SignInParams = data.into_inner().try_into()?;
|
||||||
let user = session.sign_in(params).await?;
|
let user_detail = session.sign_in(params).await?;
|
||||||
let user_detail = UserDetail::from(user);
|
|
||||||
data_result(user_detail)
|
data_result(user_detail)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,12 +18,9 @@ pub async fn sign_in(
|
|||||||
name = %data.name,
|
name = %data.name,
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
pub async fn sign_up(
|
pub async fn sign_up(data: Data<SignUpRequest>, session: Unit<Arc<UserSession>>) -> DataResult<UserDetail, UserError> {
|
||||||
data: Data<SignUpRequest>,
|
|
||||||
session: Unit<Arc<UserSession>>,
|
|
||||||
) -> DataResult<UserDetail, UserError> {
|
|
||||||
let params: SignUpParams = data.into_inner().try_into()?;
|
let params: SignUpParams = data.into_inner().try_into()?;
|
||||||
let user = session.sign_up(params).await?;
|
let user_detail = session.sign_up(params).await?;
|
||||||
let user_detail = UserDetail::from(user);
|
|
||||||
data_result(user_detail)
|
data_result(user_detail)
|
||||||
}
|
}
|
||||||
|
@ -217,8 +217,8 @@ impl ::protobuf::reflect::ProtobufValue for UserError {
|
|||||||
pub enum ErrorCode {
|
pub enum ErrorCode {
|
||||||
Unknown = 0,
|
Unknown = 0,
|
||||||
UserDatabaseInitFailed = 1,
|
UserDatabaseInitFailed = 1,
|
||||||
UserDatabaseWriteLocked = 2,
|
AcquireWriteLockedFailed = 2,
|
||||||
UserDatabaseReadLocked = 3,
|
AcquireReadLockedFailed = 3,
|
||||||
UserDatabaseDidNotMatch = 4,
|
UserDatabaseDidNotMatch = 4,
|
||||||
UserDatabaseInternalError = 5,
|
UserDatabaseInternalError = 5,
|
||||||
SqlInternalError = 6,
|
SqlInternalError = 6,
|
||||||
@ -253,8 +253,8 @@ impl ::protobuf::ProtobufEnum for ErrorCode {
|
|||||||
match value {
|
match value {
|
||||||
0 => ::std::option::Option::Some(ErrorCode::Unknown),
|
0 => ::std::option::Option::Some(ErrorCode::Unknown),
|
||||||
1 => ::std::option::Option::Some(ErrorCode::UserDatabaseInitFailed),
|
1 => ::std::option::Option::Some(ErrorCode::UserDatabaseInitFailed),
|
||||||
2 => ::std::option::Option::Some(ErrorCode::UserDatabaseWriteLocked),
|
2 => ::std::option::Option::Some(ErrorCode::AcquireWriteLockedFailed),
|
||||||
3 => ::std::option::Option::Some(ErrorCode::UserDatabaseReadLocked),
|
3 => ::std::option::Option::Some(ErrorCode::AcquireReadLockedFailed),
|
||||||
4 => ::std::option::Option::Some(ErrorCode::UserDatabaseDidNotMatch),
|
4 => ::std::option::Option::Some(ErrorCode::UserDatabaseDidNotMatch),
|
||||||
5 => ::std::option::Option::Some(ErrorCode::UserDatabaseInternalError),
|
5 => ::std::option::Option::Some(ErrorCode::UserDatabaseInternalError),
|
||||||
6 => ::std::option::Option::Some(ErrorCode::SqlInternalError),
|
6 => ::std::option::Option::Some(ErrorCode::SqlInternalError),
|
||||||
@ -286,8 +286,8 @@ impl ::protobuf::ProtobufEnum for ErrorCode {
|
|||||||
static values: &'static [ErrorCode] = &[
|
static values: &'static [ErrorCode] = &[
|
||||||
ErrorCode::Unknown,
|
ErrorCode::Unknown,
|
||||||
ErrorCode::UserDatabaseInitFailed,
|
ErrorCode::UserDatabaseInitFailed,
|
||||||
ErrorCode::UserDatabaseWriteLocked,
|
ErrorCode::AcquireWriteLockedFailed,
|
||||||
ErrorCode::UserDatabaseReadLocked,
|
ErrorCode::AcquireReadLockedFailed,
|
||||||
ErrorCode::UserDatabaseDidNotMatch,
|
ErrorCode::UserDatabaseDidNotMatch,
|
||||||
ErrorCode::UserDatabaseInternalError,
|
ErrorCode::UserDatabaseInternalError,
|
||||||
ErrorCode::SqlInternalError,
|
ErrorCode::SqlInternalError,
|
||||||
@ -341,10 +341,10 @@ impl ::protobuf::reflect::ProtobufValue for ErrorCode {
|
|||||||
static file_descriptor_proto_data: &'static [u8] = b"\
|
static file_descriptor_proto_data: &'static [u8] = b"\
|
||||||
\n\x0cerrors.proto\"=\n\tUserError\x12\x1e\n\x04code\x18\x01\x20\x01(\
|
\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*\
|
\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\
|
\xbb\x05\n\tErrorCode\x12\x0b\n\x07Unknown\x10\0\x12\x1a\n\x16UserDataba\
|
||||||
seInitFailed\x10\x01\x12\x1b\n\x17UserDatabaseWriteLocked\x10\x02\x12\
|
seInitFailed\x10\x01\x12\x1c\n\x18AcquireWriteLockedFailed\x10\x02\x12\
|
||||||
\x1a\n\x16UserDatabaseReadLocked\x10\x03\x12\x1b\n\x17UserDatabaseDidNot\
|
\x1b\n\x17AcquireReadLockedFailed\x10\x03\x12\x1b\n\x17UserDatabaseDidNo\
|
||||||
Match\x10\x04\x12\x1d\n\x19UserDatabaseInternalError\x10\x05\x12\x14\n\
|
tMatch\x10\x04\x12\x1d\n\x19UserDatabaseInternalError\x10\x05\x12\x14\n\
|
||||||
\x10SqlInternalError\x10\x06\x12\x18\n\x14DatabaseConnectError\x10\x07\
|
\x10SqlInternalError\x10\x06\x12\x18\n\x14DatabaseConnectError\x10\x07\
|
||||||
\x12\x13\n\x0fUserNotLoginYet\x10\n\x12\x17\n\x13ReadCurrentIdFailed\x10\
|
\x12\x13\n\x0fUserNotLoginYet\x10\n\x12\x17\n\x13ReadCurrentIdFailed\x10\
|
||||||
\x0b\x12\x18\n\x14WriteCurrentIdFailed\x10\x0c\x12\x10\n\x0cEmailIsEmpty\
|
\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\
|
\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\
|
\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\
|
\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\
|
\x05\0\x02\x02\x12\x03\t\x04!\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\
|
\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\x1f\n\x0c\n\x05\x05\0\x02\x03\x01\x12\x03\n\x04\
|
\0\x02\x03\x12\x03\n\x04\x20\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\
|
\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\
|
\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\
|
\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\
|
\x05\0\x02\x05\x12\x03\x0c\x04\"\n\x0c\n\x05\x05\0\x02\x05\x01\x12\x03\
|
||||||
|
@ -7,8 +7,8 @@ message UserError {
|
|||||||
enum ErrorCode {
|
enum ErrorCode {
|
||||||
Unknown = 0;
|
Unknown = 0;
|
||||||
UserDatabaseInitFailed = 1;
|
UserDatabaseInitFailed = 1;
|
||||||
UserDatabaseWriteLocked = 2;
|
AcquireWriteLockedFailed = 2;
|
||||||
UserDatabaseReadLocked = 3;
|
AcquireReadLockedFailed = 3;
|
||||||
UserDatabaseDidNotMatch = 4;
|
UserDatabaseDidNotMatch = 4;
|
||||||
UserDatabaseInternalError = 5;
|
UserDatabaseInternalError = 5;
|
||||||
SqlInternalError = 6;
|
SqlInternalError = 6;
|
||||||
|
@ -15,21 +15,22 @@ impl UserServerAPI for UserServerMock {
|
|||||||
let uid = uuid();
|
let uid = uuid();
|
||||||
ResultFuture::new(async move {
|
ResultFuture::new(async move {
|
||||||
Ok(SignUpResponse {
|
Ok(SignUpResponse {
|
||||||
user_id: uid,
|
user_id: uid.clone(),
|
||||||
name: params.name,
|
name: params.name,
|
||||||
email: params.email,
|
email: params.email,
|
||||||
token: "fake token".to_owned(),
|
token: uid,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_in(&self, params: SignInParams) -> ResultFuture<SignInResponse, UserError> {
|
fn sign_in(&self, params: SignInParams) -> ResultFuture<SignInResponse, UserError> {
|
||||||
|
let user_id = uuid();
|
||||||
ResultFuture::new(async {
|
ResultFuture::new(async {
|
||||||
Ok(SignInResponse {
|
Ok(SignInResponse {
|
||||||
uid: uuid(),
|
uid: user_id.clone(),
|
||||||
name: "fake name".to_owned(),
|
name: "fake name".to_owned(),
|
||||||
email: params.email,
|
email: params.email,
|
||||||
token: "fake token".to_string(),
|
token: user_id,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,8 @@ use flowy_database::{DBConnection, Database};
|
|||||||
use flowy_sqlite::ConnectionPool;
|
use flowy_sqlite::ConnectionPool;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::{lock_api::RwLockReadGuard, Mutex, RawRwLock, RwLock};
|
||||||
use std::{
|
use std::{collections::HashMap, sync::Arc, time::Duration};
|
||||||
collections::HashMap,
|
|
||||||
sync::{Arc, RwLock},
|
|
||||||
};
|
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref DB: RwLock<Option<Database>> = RwLock::new(None);
|
static ref DB: RwLock<Option<Database>> = RwLock::new(None);
|
||||||
}
|
}
|
||||||
@ -18,46 +14,42 @@ pub(crate) struct UserDB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl UserDB {
|
impl UserDB {
|
||||||
pub(crate) fn new(db_dir: &str) -> Self {
|
pub(crate) fn new(db_dir: &str) -> Self { Self { db_dir: db_dir.to_owned() } }
|
||||||
Self {
|
|
||||||
db_dir: db_dir.to_owned(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn open_user_db(&self, user_id: &str) -> Result<(), UserError> {
|
fn open_user_db(&self, user_id: &str) -> Result<(), UserError> {
|
||||||
if user_id.is_empty() {
|
if user_id.is_empty() {
|
||||||
return Err(ErrorBuilder::new(ErrorCode::UserDatabaseInitFailed)
|
return Err(ErrorBuilder::new(ErrorCode::UserDatabaseInitFailed).msg("user id is empty").build());
|
||||||
.msg("user id is empty")
|
|
||||||
.build());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log::info!("open user db {}", user_id);
|
||||||
let dir = format!("{}/{}", self.db_dir, user_id);
|
let dir = format!("{}/{}", self.db_dir, user_id);
|
||||||
let db = flowy_database::init(&dir).map_err(|e| {
|
let db = flowy_database::init(&dir).map_err(|e| {
|
||||||
log::error!("flowy_database::init failed, {:?}", e);
|
log::error!("init user db failed, {:?}, user_id: {}", e, user_id);
|
||||||
ErrorBuilder::new(ErrorCode::UserDatabaseInitFailed)
|
ErrorBuilder::new(ErrorCode::UserDatabaseInitFailed).error(e).build()
|
||||||
.error(e)
|
|
||||||
.build()
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let mut db_map = DB_MAP.write().map_err(|e| {
|
match DB_MAP.try_write_for(Duration::from_millis(300)) {
|
||||||
ErrorBuilder::new(ErrorCode::UserDatabaseWriteLocked)
|
None => Err(ErrorBuilder::new(ErrorCode::AcquireWriteLockedFailed)
|
||||||
.error(e)
|
.msg(format!("Open user db failed"))
|
||||||
.build()
|
.build()),
|
||||||
})?;
|
Some(mut write_guard) => {
|
||||||
|
write_guard.insert(user_id.to_owned(), db);
|
||||||
db_map.insert(user_id.to_owned(), db);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn close_user_db(&self, user_id: &str) -> Result<(), UserError> {
|
pub(crate) fn close_user_db(&self, user_id: &str) -> Result<(), UserError> {
|
||||||
let mut db_map = DB_MAP.write().map_err(|e| {
|
match DB_MAP.try_write_for(Duration::from_millis(300)) {
|
||||||
ErrorBuilder::new(ErrorCode::UserDatabaseWriteLocked)
|
None => Err(ErrorBuilder::new(ErrorCode::AcquireWriteLockedFailed)
|
||||||
.msg(format!("Close user db failed. {:?}", e))
|
.msg(format!("Close user db failed"))
|
||||||
.build()
|
.build()),
|
||||||
})?;
|
Some(mut write_guard) => {
|
||||||
set_user_db_init(false, user_id);
|
set_user_db_init(false, user_id);
|
||||||
db_map.remove(user_id);
|
write_guard.remove(user_id);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_connection(&self, user_id: &str) -> Result<DBConnection, UserError> {
|
pub(crate) fn get_connection(&self, user_id: &str) -> Result<DBConnection, UserError> {
|
||||||
@ -66,22 +58,28 @@ impl UserDB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_pool(&self, user_id: &str) -> Result<Arc<ConnectionPool>, UserError> {
|
pub(crate) fn get_pool(&self, user_id: &str) -> Result<Arc<ConnectionPool>, UserError> {
|
||||||
|
// 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) {
|
if !is_user_db_init(user_id) {
|
||||||
let _ = self.open_user_db(user_id)?;
|
let _ = self.open_user_db(user_id)?;
|
||||||
set_user_db_init(true, user_id);
|
set_user_db_init(true, user_id);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
let db_map = DB_MAP.read().map_err(|e| {
|
match DB_MAP.try_read_for(Duration::from_millis(300)) {
|
||||||
ErrorBuilder::new(ErrorCode::UserDatabaseReadLocked)
|
None => Err(ErrorBuilder::new(ErrorCode::AcquireReadLockedFailed)
|
||||||
.error(e)
|
.msg(format!("Read user db failed"))
|
||||||
.build()
|
.build()),
|
||||||
})?;
|
Some(read_guard) => match read_guard.get(user_id) {
|
||||||
|
|
||||||
match db_map.get(user_id) {
|
|
||||||
None => Err(ErrorBuilder::new(ErrorCode::UserDatabaseInitFailed)
|
None => Err(ErrorBuilder::new(ErrorCode::UserDatabaseInitFailed)
|
||||||
.msg("Get connection failed. The database is not initialization")
|
.msg("Get connection failed. The database is not initialization")
|
||||||
.build()),
|
.build()),
|
||||||
Some(database) => Ok(database.get_pool()),
|
Some(database) => Ok(database.get_pool()),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,14 +88,15 @@ lazy_static! {
|
|||||||
static ref DB_MAP: RwLock<HashMap<String, Database>> = RwLock::new(HashMap::new());
|
static ref DB_MAP: RwLock<HashMap<String, Database>> = RwLock::new(HashMap::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
static INIT_FLAG_MAP: Lazy<Mutex<HashMap<String, bool>>> = Lazy::new(|| Mutex::new(HashMap::new()));
|
static INIT_LOCK: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));
|
||||||
|
static INIT_RECORD: Lazy<Mutex<HashMap<String, bool>>> = Lazy::new(|| Mutex::new(HashMap::new()));
|
||||||
fn set_user_db_init(is_init: bool, user_id: &str) {
|
fn set_user_db_init(is_init: bool, user_id: &str) {
|
||||||
let mut flag_map = INIT_FLAG_MAP.lock();
|
let mut record = INIT_RECORD.lock();
|
||||||
flag_map.insert(user_id.to_owned(), is_init);
|
record.insert(user_id.to_owned(), is_init);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_user_db_init(user_id: &str) -> bool {
|
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,
|
None => false,
|
||||||
Some(flag) => flag.clone(),
|
Some(flag) => flag.clone(),
|
||||||
}
|
}
|
||||||
|
@ -69,22 +69,36 @@ impl UserSession {
|
|||||||
self.database.get_pool(&user_id)
|
self.database.get_pool(&user_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn sign_in(&self, params: SignInParams) -> Result<UserTable, UserError> {
|
pub async fn sign_in(&self, params: SignInParams) -> Result<UserDetail, UserError> {
|
||||||
|
if self.is_login(¶ms.email) {
|
||||||
|
self.user_detail().await
|
||||||
|
} else {
|
||||||
let resp = self.server.sign_in(params).await?;
|
let resp = self.server.sign_in(params).await?;
|
||||||
let session = Session::new(&resp.uid, &resp.token);
|
let session = Session::new(&resp.uid, &resp.token, &resp.email);
|
||||||
let _ = self.set_session(Some(session))?;
|
let _ = self.set_session(Some(session))?;
|
||||||
let user_table = self.save_user(resp.into()).await?;
|
let user_table = self.save_user(resp.into()).await?;
|
||||||
|
let user_detail = UserDetail::from(user_table);
|
||||||
Ok(user_table)
|
Ok(user_detail)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn sign_up(&self, params: SignUpParams) -> Result<UserTable, UserError> {
|
pub async fn sign_up(&self, params: SignUpParams) -> Result<UserDetail, UserError> {
|
||||||
|
// 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 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 _ = self.set_session(Some(session))?;
|
||||||
let user_table = self.save_user(resp.into()).await?;
|
let user_table = self.save_user(resp.into()).await?;
|
||||||
|
let user_detail = UserDetail::from(user_table);
|
||||||
Ok(user_table)
|
Ok(user_detail)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn sign_out(&self) -> Result<(), UserError> {
|
pub async fn sign_out(&self) -> Result<(), UserError> {
|
||||||
@ -170,6 +184,7 @@ impl UserSession {
|
|||||||
*self.session.write() = session;
|
*self.session.write() = session;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_session(&self) -> Result<Session, UserError> {
|
fn get_session(&self) -> Result<Session, UserError> {
|
||||||
let mut session = { (*self.session.read()).clone() };
|
let mut session = { (*self.session.read()).clone() };
|
||||||
if session.is_none() {
|
if session.is_none() {
|
||||||
@ -187,6 +202,13 @@ impl UserSession {
|
|||||||
Some(session) => Ok(session),
|
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<ConnectionPool>, params: UpdateUserParams) -> Result<(), UserError> {
|
pub async fn update_user(_server: Server, pool: Arc<ConnectionPool>, params: UpdateUserParams) -> Result<(), UserError> {
|
||||||
@ -213,13 +235,15 @@ const SESSION_CACHE_KEY: &str = "session_cache_key";
|
|||||||
struct Session {
|
struct Session {
|
||||||
user_id: String,
|
user_id: String,
|
||||||
token: String,
|
token: String,
|
||||||
|
email: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Session {
|
impl Session {
|
||||||
pub fn new(user_id: &str, token: &str) -> Self {
|
pub fn new(user_id: &str, token: &str, email: &str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
user_id: user_id.to_owned(),
|
user_id: user_id.to_owned(),
|
||||||
token: token.to_owned(),
|
token: token.to_owned(),
|
||||||
|
email: email.to_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
use crate::helper::*;
|
use crate::helper::*;
|
||||||
|
use flowy_test::builder::UserTestBuilder;
|
||||||
use flowy_user::{errors::ErrorCode, event::UserEvent::*, prelude::*};
|
use flowy_user::{errors::ErrorCode, event::UserEvent::*, prelude::*};
|
||||||
use serial_test::*;
|
use serial_test::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn sign_up_success() {
|
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);
|
log::info!("{:?}", user_detail);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,16 +17,11 @@ fn sign_up_with_invalid_email() {
|
|||||||
let request = SignUpRequest {
|
let request = SignUpRequest {
|
||||||
email: email.to_string(),
|
email: email.to_string(),
|
||||||
name: valid_name(),
|
name: valid_name(),
|
||||||
password: valid_password(),
|
password: login_password(),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
TestBuilder::new()
|
UserTestBuilder::new().event(SignUp).request(request).sync_send().error().code,
|
||||||
.event(SignUp)
|
|
||||||
.request(request)
|
|
||||||
.sync_send()
|
|
||||||
.error()
|
|
||||||
.code,
|
|
||||||
ErrorCode::EmailFormatInvalid
|
ErrorCode::EmailFormatInvalid
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -40,27 +36,23 @@ fn sign_up_with_invalid_password() {
|
|||||||
password,
|
password,
|
||||||
};
|
};
|
||||||
|
|
||||||
TestBuilder::new()
|
UserTestBuilder::new().event(SignUp).request(request).sync_send().assert_error();
|
||||||
.event(SignUp)
|
|
||||||
.request(request)
|
|
||||||
.sync_send()
|
|
||||||
.assert_error();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn sign_in_success() {
|
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 {
|
let request = SignInRequest {
|
||||||
email: context.user_detail.email,
|
email: context.user_detail.email,
|
||||||
password: context.password,
|
password: context.password,
|
||||||
};
|
};
|
||||||
|
|
||||||
let response = TestBuilder::new()
|
let response = UserTestBuilder::new()
|
||||||
.event(SignIn)
|
.event(SignIn)
|
||||||
.request(request)
|
.request(request)
|
||||||
.sync_send()
|
.sync_send()
|
||||||
@ -74,16 +66,11 @@ fn sign_in_with_invalid_email() {
|
|||||||
for email in invalid_email_test_case() {
|
for email in invalid_email_test_case() {
|
||||||
let request = SignInRequest {
|
let request = SignInRequest {
|
||||||
email: email.to_string(),
|
email: email.to_string(),
|
||||||
password: valid_password(),
|
password: login_password(),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
TestBuilder::new()
|
UserTestBuilder::new().event(SignIn).request(request).sync_send().error().code,
|
||||||
.event(SignIn)
|
|
||||||
.request(request)
|
|
||||||
.sync_send()
|
|
||||||
.error()
|
|
||||||
.code,
|
|
||||||
ErrorCode::EmailFormatInvalid
|
ErrorCode::EmailFormatInvalid
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -98,10 +85,6 @@ fn sign_in_with_invalid_password() {
|
|||||||
password,
|
password,
|
||||||
};
|
};
|
||||||
|
|
||||||
TestBuilder::new()
|
UserTestBuilder::new().event(SignIn).request(request).sync_send().assert_error();
|
||||||
.event(SignIn)
|
|
||||||
.request(request)
|
|
||||||
.sync_send()
|
|
||||||
.assert_error();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
pub use flowy_test::builder::TestBuilder;
|
pub use flowy_test::{
|
||||||
|
builder::*,
|
||||||
pub use flowy_test::prelude::{random_email, valid_password};
|
prelude::{login_password, random_email},
|
||||||
|
};
|
||||||
|
|
||||||
pub(crate) fn invalid_email_test_case() -> Vec<String> {
|
pub(crate) fn invalid_email_test_case() -> Vec<String> {
|
||||||
// https://gist.github.com/cjaoude/fd9910626629b53c4d25
|
// https://gist.github.com/cjaoude/fd9910626629b53c4d25
|
||||||
|
@ -1,28 +1,22 @@
|
|||||||
use crate::helper::*;
|
use crate::helper::*;
|
||||||
use flowy_infra::uuid;
|
use flowy_infra::uuid;
|
||||||
|
use flowy_test::builder::UserTestBuilder;
|
||||||
use flowy_user::{errors::ErrorCode, event::UserEvent::*, prelude::*};
|
use flowy_user::{errors::ErrorCode, event::UserEvent::*, prelude::*};
|
||||||
use serial_test::*;
|
use serial_test::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn user_status_get_failed() {
|
fn user_status_get_failed() {
|
||||||
let user_detail = TestBuilder::new()
|
let tester = UserTestBuilder::new().event(GetUserProfile).assert_error().sync_send();
|
||||||
.event(GetUserProfile)
|
assert!(tester.get_user_detail().is_none())
|
||||||
.assert_error()
|
|
||||||
.sync_send()
|
|
||||||
.user_detail;
|
|
||||||
assert!(user_detail.is_none())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn user_detail_get() {
|
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()
|
let user_detail2 = UserTestBuilder::new().event(GetUserProfile).sync_send().parse::<UserDetail>();
|
||||||
.event(GetUserProfile)
|
|
||||||
.sync_send()
|
|
||||||
.parse::<UserDetail>();
|
|
||||||
|
|
||||||
assert_eq!(user_detail, user_detail2);
|
assert_eq!(user_detail, user_detail2);
|
||||||
}
|
}
|
||||||
@ -30,15 +24,12 @@ fn user_detail_get() {
|
|||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn user_update_with_name() {
|
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 new_name = "hello_world".to_owned();
|
||||||
let request = UpdateUserRequest::new(&user_detail.id).name(&new_name);
|
let request = UpdateUserRequest::new(&user_detail.id).name(&new_name);
|
||||||
let _ = TestBuilder::new()
|
let _ = UserTestBuilder::new().event(UpdateUser).request(request).sync_send();
|
||||||
.event(UpdateUser)
|
|
||||||
.request(request)
|
|
||||||
.sync_send();
|
|
||||||
|
|
||||||
let user_detail = TestBuilder::new()
|
let user_detail = UserTestBuilder::new()
|
||||||
.event(GetUserProfile)
|
.event(GetUserProfile)
|
||||||
.assert_error()
|
.assert_error()
|
||||||
.sync_send()
|
.sync_send()
|
||||||
@ -50,16 +41,13 @@ fn user_update_with_name() {
|
|||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn user_update_with_email() {
|
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 new_email = format!("{}@gmai.com", uuid());
|
||||||
let request = UpdateUserRequest::new(&user_detail.id).email(&new_email);
|
let request = UpdateUserRequest::new(&user_detail.id).email(&new_email);
|
||||||
|
|
||||||
let _ = TestBuilder::new()
|
let _ = UserTestBuilder::new().event(UpdateUser).request(request).sync_send();
|
||||||
.event(UpdateUser)
|
|
||||||
.request(request)
|
|
||||||
.sync_send();
|
|
||||||
|
|
||||||
let user_detail = TestBuilder::new()
|
let user_detail = UserTestBuilder::new()
|
||||||
.event(GetUserProfile)
|
.event(GetUserProfile)
|
||||||
.assert_error()
|
.assert_error()
|
||||||
.sync_send()
|
.sync_send()
|
||||||
@ -71,11 +59,11 @@ fn user_update_with_email() {
|
|||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn user_update_with_password() {
|
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 new_password = "H123world!".to_owned();
|
||||||
let request = UpdateUserRequest::new(&user_detail.id).password(&new_password);
|
let request = UpdateUserRequest::new(&user_detail.id).password(&new_password);
|
||||||
|
|
||||||
let _ = TestBuilder::new()
|
let _ = UserTestBuilder::new()
|
||||||
.event(UpdateUser)
|
.event(UpdateUser)
|
||||||
.request(request)
|
.request(request)
|
||||||
.sync_send()
|
.sync_send()
|
||||||
@ -85,16 +73,11 @@ fn user_update_with_password() {
|
|||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn user_update_with_invalid_email() {
|
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() {
|
for email in invalid_email_test_case() {
|
||||||
let request = UpdateUserRequest::new(&user_detail.id).email(&email);
|
let request = UpdateUserRequest::new(&user_detail.id).email(&email);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
TestBuilder::new()
|
UserTestBuilder::new().event(UpdateUser).request(request).sync_send().error().code,
|
||||||
.event(UpdateUser)
|
|
||||||
.request(request)
|
|
||||||
.sync_send()
|
|
||||||
.error()
|
|
||||||
.code,
|
|
||||||
ErrorCode::EmailFormatInvalid
|
ErrorCode::EmailFormatInvalid
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -103,27 +86,19 @@ fn user_update_with_invalid_email() {
|
|||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn user_update_with_invalid_password() {
|
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() {
|
for password in invalid_password_test_case() {
|
||||||
let request = UpdateUserRequest::new(&user_detail.id).password(&password);
|
let request = UpdateUserRequest::new(&user_detail.id).password(&password);
|
||||||
|
|
||||||
TestBuilder::new()
|
UserTestBuilder::new().event(UpdateUser).request(request).sync_send().assert_error();
|
||||||
.event(UpdateUser)
|
|
||||||
.request(request)
|
|
||||||
.sync_send()
|
|
||||||
.assert_error();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[serial]
|
#[serial]
|
||||||
fn user_update_with_invalid_name() {
|
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("");
|
let request = UpdateUserRequest::new(&user_detail.id).name("");
|
||||||
|
|
||||||
TestBuilder::new()
|
UserTestBuilder::new().event(UpdateUser).request(request).sync_send().assert_error();
|
||||||
.event(UpdateUser)
|
|
||||||
.request(request)
|
|
||||||
.sync_send()
|
|
||||||
.assert_error();
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::helper::*;
|
use crate::helper::*;
|
||||||
|
|
||||||
|
use flowy_test::builder::UserTestBuilder;
|
||||||
use flowy_workspace::entities::{
|
use flowy_workspace::entities::{
|
||||||
app::{QueryAppRequest, UpdateAppRequest},
|
app::{QueryAppRequest, UpdateAppRequest},
|
||||||
view::*,
|
view::*,
|
||||||
@ -7,6 +8,7 @@ use flowy_workspace::entities::{
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn app_create() {
|
fn app_create() {
|
||||||
|
let _ = UserTestBuilder::new().sign_up();
|
||||||
let workspace = create_workspace("Workspace", "");
|
let workspace = create_workspace("Workspace", "");
|
||||||
let app = create_app("App A", "AppFlowy Github Project", &workspace.id);
|
let app = create_app("App A", "AppFlowy Github Project", &workspace.id);
|
||||||
dbg!(&app);
|
dbg!(&app);
|
||||||
@ -15,6 +17,8 @@ fn app_create() {
|
|||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn app_delete() {
|
fn app_delete() {
|
||||||
|
let _ = UserTestBuilder::new().sign_up();
|
||||||
|
|
||||||
let workspace = create_workspace("Workspace", "");
|
let workspace = create_workspace("Workspace", "");
|
||||||
let app = create_app("App A", "AppFlowy Github Project", &workspace.id);
|
let app = create_app("App A", "AppFlowy Github Project", &workspace.id);
|
||||||
delete_app(&app.id);
|
delete_app(&app.id);
|
||||||
@ -24,6 +28,8 @@ fn app_delete() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn app_read() {
|
fn app_read() {
|
||||||
|
let _ = UserTestBuilder::new().sign_up();
|
||||||
|
|
||||||
let workspace = create_workspace("Workspace", "");
|
let workspace = create_workspace("Workspace", "");
|
||||||
let app = create_app("App A", "AppFlowy Github Project", &workspace.id);
|
let app = create_app("App A", "AppFlowy Github Project", &workspace.id);
|
||||||
let query = QueryAppRequest::new(&app.id);
|
let query = QueryAppRequest::new(&app.id);
|
||||||
@ -33,6 +39,7 @@ fn app_read() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn app_create_with_view() {
|
fn app_create_with_view() {
|
||||||
|
let _a = UserTestBuilder::new().sign_up();
|
||||||
let workspace = create_workspace("Workspace", "");
|
let workspace = create_workspace("Workspace", "");
|
||||||
let app = create_app("App A", "AppFlowy Github Project", &workspace.id);
|
let app = create_app("App A", "AppFlowy Github Project", &workspace.id);
|
||||||
let request_a = CreateViewRequest {
|
let request_a = CreateViewRequest {
|
||||||
@ -63,6 +70,7 @@ fn app_create_with_view() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn app_set_trash_flag() {
|
fn app_set_trash_flag() {
|
||||||
|
let _ = UserTestBuilder::new().sign_up();
|
||||||
let app_id = create_app_with_trash_flag();
|
let app_id = create_app_with_trash_flag();
|
||||||
let query = QueryAppRequest::new(&app_id).set_is_trash(true);
|
let query = QueryAppRequest::new(&app_id).set_is_trash(true);
|
||||||
let _ = read_app(query);
|
let _ = read_app(query);
|
||||||
@ -71,6 +79,7 @@ fn app_set_trash_flag() {
|
|||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn app_set_trash_flag_2() {
|
fn app_set_trash_flag_2() {
|
||||||
|
let _ = UserTestBuilder::new().sign_up();
|
||||||
let app_id = create_app_with_trash_flag();
|
let app_id = create_app_with_trash_flag();
|
||||||
let query = QueryAppRequest::new(&app_id);
|
let query = QueryAppRequest::new(&app_id);
|
||||||
let _ = read_app(query);
|
let _ = read_app(query);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
pub use flowy_test::builder::AnnieTestBuilder;
|
use flowy_test::builder::{UserTestBuilder, WorkspaceTestBuilder};
|
||||||
use flowy_workspace::{
|
use flowy_workspace::{
|
||||||
entities::{app::*, view::*, workspace::*},
|
entities::{app::*, view::*, workspace::*},
|
||||||
event::WorkspaceEvent::*,
|
event::WorkspaceEvent::*,
|
||||||
@ -17,7 +17,7 @@ pub fn create_workspace(name: &str, desc: &str) -> Workspace {
|
|||||||
desc: desc.to_owned(),
|
desc: desc.to_owned(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let workspace = AnnieTestBuilder::new()
|
let workspace = WorkspaceTestBuilder::new()
|
||||||
.event(CreateWorkspace)
|
.event(CreateWorkspace)
|
||||||
.request(request)
|
.request(request)
|
||||||
.sync_send()
|
.sync_send()
|
||||||
@ -26,13 +26,13 @@ pub fn create_workspace(name: &str, desc: &str) -> Workspace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_workspaces(request: QueryWorkspaceRequest) -> Option<Workspace> {
|
pub fn read_workspaces(request: QueryWorkspaceRequest) -> Option<Workspace> {
|
||||||
let mut repeated_workspace = AnnieTestBuilder::new()
|
let mut repeated_workspace = WorkspaceTestBuilder::new()
|
||||||
.event(ReadWorkspaces)
|
.event(ReadWorkspaces)
|
||||||
.request(request)
|
.request(request)
|
||||||
.sync_send()
|
.sync_send()
|
||||||
.parse::<RepeatedWorkspace>();
|
.parse::<RepeatedWorkspace>();
|
||||||
|
|
||||||
debug_assert_eq!(repeated_workspace.len(), 1);
|
debug_assert_eq!(repeated_workspace.len(), 1, "Default workspace not found");
|
||||||
repeated_workspace.drain(..1).collect::<Vec<Workspace>>().pop()
|
repeated_workspace.drain(..1).collect::<Vec<Workspace>>().pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ pub fn create_app(name: &str, desc: &str, workspace_id: &str) -> App {
|
|||||||
color_style: Default::default(),
|
color_style: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let app = AnnieTestBuilder::new()
|
let app = WorkspaceTestBuilder::new()
|
||||||
.event(CreateApp)
|
.event(CreateApp)
|
||||||
.request(create_app_request)
|
.request(create_app_request)
|
||||||
.sync_send()
|
.sync_send()
|
||||||
@ -57,19 +57,23 @@ pub fn delete_app(app_id: &str) {
|
|||||||
app_id: app_id.to_string(),
|
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 {
|
pub fn read_app(request: QueryAppRequest) -> App {
|
||||||
let app = AnnieTestBuilder::new().event(ReadApp).request(request).sync_send().parse::<App>();
|
let app = WorkspaceTestBuilder::new()
|
||||||
|
.event(ReadApp)
|
||||||
|
.request(request)
|
||||||
|
.sync_send()
|
||||||
|
.parse::<App>();
|
||||||
|
|
||||||
app
|
app
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_view_with_request(request: CreateViewRequest) -> View {
|
pub fn create_view_with_request(request: CreateViewRequest) -> View {
|
||||||
let view = AnnieTestBuilder::new()
|
let view = WorkspaceTestBuilder::new()
|
||||||
.event(CreateView)
|
.event(CreateView)
|
||||||
.request(request)
|
.request(request)
|
||||||
.sync_send()
|
.sync_send()
|
||||||
@ -78,9 +82,8 @@ pub fn create_view_with_request(request: CreateViewRequest) -> View {
|
|||||||
view
|
view
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_view() -> View {
|
pub fn create_view(workspace_id: &str) -> View {
|
||||||
let workspace = create_workspace("Workspace", "");
|
let app = create_app("App A", "AppFlowy Github Project", workspace_id);
|
||||||
let app = create_app("App A", "AppFlowy Github Project", &workspace.id);
|
|
||||||
let request = CreateViewRequest {
|
let request = CreateViewRequest {
|
||||||
belong_to_id: app.id.clone(),
|
belong_to_id: app.id.clone(),
|
||||||
name: "View A".to_string(),
|
name: "View A".to_string(),
|
||||||
@ -92,6 +95,12 @@ pub fn create_view() -> View {
|
|||||||
create_view_with_request(request)
|
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::<View>() }
|
pub fn read_view(request: QueryViewRequest) -> View {
|
||||||
|
WorkspaceTestBuilder::new()
|
||||||
|
.event(ReadView)
|
||||||
|
.request(request)
|
||||||
|
.sync_send()
|
||||||
|
.parse::<View>()
|
||||||
|
}
|
||||||
|
@ -1,12 +1,19 @@
|
|||||||
use crate::helper::*;
|
use crate::helper::*;
|
||||||
|
|
||||||
|
use flowy_test::builder::UserTestBuilder;
|
||||||
use flowy_workspace::entities::view::*;
|
use flowy_workspace::entities::view::*;
|
||||||
|
|
||||||
#[test]
|
#[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]
|
#[test]
|
||||||
fn view_set_trash_flag() {
|
fn view_set_trash_flag() {
|
||||||
|
let _ = UserTestBuilder::new().sign_up();
|
||||||
let view_id = create_view_with_trash_flag();
|
let view_id = create_view_with_trash_flag();
|
||||||
let query = QueryViewRequest::new(&view_id).set_is_trash(true);
|
let query = QueryViewRequest::new(&view_id).set_is_trash(true);
|
||||||
let _ = read_view(query);
|
let _ = read_view(query);
|
||||||
@ -15,13 +22,16 @@ fn view_set_trash_flag() {
|
|||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn view_set_trash_flag2() {
|
fn view_set_trash_flag2() {
|
||||||
|
let _ = UserTestBuilder::new().sign_up();
|
||||||
|
|
||||||
let view_id = create_view_with_trash_flag();
|
let view_id = create_view_with_trash_flag();
|
||||||
let query = QueryViewRequest::new(&view_id);
|
let query = QueryViewRequest::new(&view_id);
|
||||||
let _ = read_view(query);
|
let _ = read_view(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_view_with_trash_flag() -> String {
|
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 {
|
let request = UpdateViewRequest {
|
||||||
view_id: view.id.clone(),
|
view_id: view.id.clone(),
|
||||||
name: None,
|
name: None,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::helper::*;
|
use crate::helper::*;
|
||||||
|
use flowy_test::builder::*;
|
||||||
use flowy_workspace::{
|
use flowy_workspace::{
|
||||||
entities::workspace::{CreateWorkspaceRequest, QueryWorkspaceRequest, RepeatedWorkspace},
|
entities::workspace::{CreateWorkspaceRequest, QueryWorkspaceRequest, RepeatedWorkspace},
|
||||||
event::WorkspaceEvent::*,
|
event::WorkspaceEvent::*,
|
||||||
@ -10,11 +11,12 @@ fn workspace_create_success() { let _ = create_workspace("First workspace", "");
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn workspace_read_all() {
|
fn workspace_read_all() {
|
||||||
|
let _ = UserTestBuilder::new().sign_up();
|
||||||
let _ = create_workspace("Workspace A", "workspace_create_and_then_get_workspace_success");
|
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)
|
.event(ReadWorkspaces)
|
||||||
.request(request)
|
.request(QueryWorkspaceRequest::new())
|
||||||
.sync_send()
|
.sync_send()
|
||||||
.parse::<RepeatedWorkspace>();
|
.parse::<RepeatedWorkspace>();
|
||||||
|
|
||||||
@ -42,11 +44,15 @@ fn workspace_create_with_apps() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn workspace_create_with_invalid_name() {
|
fn workspace_create_with_invalid_name() {
|
||||||
for name in invalid_workspace_name_test_case() {
|
for name in invalid_workspace_name_test_case() {
|
||||||
let builder = AnnieTestBuilder::new();
|
let _ = UserTestBuilder::new().sign_up();
|
||||||
let request = CreateWorkspaceRequest { name, desc: "".to_owned() };
|
let request = CreateWorkspaceRequest { name, desc: "".to_owned() };
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
builder.event(CreateWorkspace).request(request).sync_send().error().code,
|
WorkspaceTestBuilder::new()
|
||||||
|
.event(CreateWorkspace)
|
||||||
|
.request(request)
|
||||||
|
.sync_send()
|
||||||
|
.error()
|
||||||
|
.code,
|
||||||
ErrorCode::WorkspaceNameInvalid
|
ErrorCode::WorkspaceNameInvalid
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -54,12 +60,16 @@ fn workspace_create_with_invalid_name() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn workspace_update_with_invalid_name() {
|
fn workspace_update_with_invalid_name() {
|
||||||
|
let _ = UserTestBuilder::new().sign_up();
|
||||||
for name in invalid_workspace_name_test_case() {
|
for name in invalid_workspace_name_test_case() {
|
||||||
let builder = AnnieTestBuilder::new();
|
|
||||||
let request = CreateWorkspaceRequest { name, desc: "".to_owned() };
|
let request = CreateWorkspaceRequest { name, desc: "".to_owned() };
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
builder.event(CreateWorkspace).request(request).sync_send().error().code,
|
WorkspaceTestBuilder::new()
|
||||||
|
.event(CreateWorkspace)
|
||||||
|
.request(request)
|
||||||
|
.sync_send()
|
||||||
|
.error()
|
||||||
|
.code,
|
||||||
ErrorCode::WorkspaceNameInvalid
|
ErrorCode::WorkspaceNameInvalid
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user