support run tests on remote

This commit is contained in:
appflowy
2021-09-04 15:12:53 +08:00
parent a6346dffae
commit ccb51234c5
32 changed files with 529 additions and 522 deletions

View File

@ -25,6 +25,7 @@ log = "0.4.14"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = {version = "1.0"} serde_json = {version = "1.0"}
bytes = { version = "1.0" } bytes = { version = "1.0" }
parking_lot = "0.11"
flowy-dispatch = {path = "../flowy-dispatch"} flowy-dispatch = {path = "../flowy-dispatch"}
flowy-sdk = {path = "../flowy-sdk"} flowy-sdk = {path = "../flowy-sdk"}

View File

@ -9,15 +9,22 @@ use crate::{
}; };
use flowy_dispatch::prelude::*; use flowy_dispatch::prelude::*;
use flowy_sdk::*; use flowy_sdk::*;
use lazy_static::lazy_static;
use parking_lot::RwLock;
use std::{ffi::CStr, os::raw::c_char, sync::Arc};
use std::{ffi::CStr, os::raw::c_char}; lazy_static! {
static ref FLOWY_SDK: RwLock<Option<Arc<FlowySDK>>> = RwLock::new(None);
}
fn dispatch() -> Arc<EventDispatch> { FLOWY_SDK.read().as_ref().unwrap().dispatch() }
#[no_mangle] #[no_mangle]
pub extern "C" fn init_sdk(path: *mut c_char) -> i64 { pub extern "C" fn init_sdk(path: *mut c_char) -> i64 {
let c_str: &CStr = unsafe { CStr::from_ptr(path) }; let c_str: &CStr = unsafe { CStr::from_ptr(path) };
let path: &str = c_str.to_str().unwrap(); let path: &str = c_str.to_str().unwrap();
log::info!("🔥 FlowySDK start running"); log::info!("🔥 FlowySDK start running");
FlowySDK::new(path).construct(); *FLOWY_SDK.write() = Some(Arc::new(FlowySDK::new(path)));
return 1; return 1;
} }
@ -25,14 +32,9 @@ pub extern "C" fn init_sdk(path: *mut c_char) -> i64 {
#[no_mangle] #[no_mangle]
pub extern "C" fn async_command(port: i64, input: *const u8, len: usize) { pub extern "C" fn async_command(port: i64, input: *const u8, len: usize) {
let request: ModuleRequest = FFIRequest::from_u8_pointer(input, len).into(); let request: ModuleRequest = FFIRequest::from_u8_pointer(input, len).into();
log::trace!( log::trace!("[FFI]: {} Async Event: {:?} with {} port", &request.id, &request.event, port);
"[FFI]: {} Async Event: {:?} with {} port",
&request.id,
&request.event,
port
);
let _ = EventDispatch::async_send_with_callback(request, move |resp: EventResponse| { let _ = EventDispatch::async_send_with_callback(dispatch(), request, move |resp: EventResponse| {
log::trace!("[FFI]: Post data to dart through {} port", port); log::trace!("[FFI]: Post data to dart through {} port", port);
Box::pin(post_to_flutter(resp, port)) Box::pin(post_to_flutter(resp, port))
}); });
@ -42,7 +44,7 @@ pub extern "C" fn async_command(port: i64, input: *const u8, len: usize) {
pub extern "C" fn sync_command(input: *const u8, len: usize) -> *const u8 { pub extern "C" fn sync_command(input: *const u8, len: usize) -> *const u8 {
let request: ModuleRequest = FFIRequest::from_u8_pointer(input, len).into(); let request: ModuleRequest = FFIRequest::from_u8_pointer(input, len).into();
log::trace!("[FFI]: {} Sync Event: {:?}", &request.id, &request.event,); log::trace!("[FFI]: {} Sync Event: {:?}", &request.id, &request.event,);
let _response = EventDispatch::sync_send(request); let _response = EventDispatch::sync_send(dispatch(), request);
// FFIResponse { } // FFIResponse { }
let response_bytes = vec![]; let response_bytes = vec![];

View File

@ -8,22 +8,17 @@ use crate::{
use derivative::*; use derivative::*;
use futures_core::future::BoxFuture; use futures_core::future::BoxFuture;
use futures_util::task::Context; use futures_util::task::Context;
use lazy_static::lazy_static;
use pin_project::pin_project; use pin_project::pin_project;
use std::{future::Future, sync::RwLock}; use std::{future::Future, sync::Arc};
use tokio::macros::support::{Pin, Poll}; use tokio::macros::support::{Pin, Poll};
lazy_static! {
static ref EVENT_DISPATCH: RwLock<Option<EventDispatch>> = RwLock::new(None);
}
pub struct EventDispatch { pub struct EventDispatch {
module_map: ModuleMap, module_map: ModuleMap,
runtime: tokio::runtime::Runtime, runtime: tokio::runtime::Runtime,
} }
impl EventDispatch { impl EventDispatch {
pub fn construct<F>(module_factory: F) pub fn construct<F>(module_factory: F) -> EventDispatch
where where
F: FnOnce() -> Vec<Module>, F: FnOnce() -> Vec<Module>,
{ {
@ -32,60 +27,88 @@ impl EventDispatch {
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 { module_map, runtime }; let dispatch = EventDispatch { module_map, runtime };
*(EVENT_DISPATCH.write().unwrap()) = Some(dispatch); dispatch
} }
pub fn async_send<Req>(request: Req) -> DispatchFuture<EventResponse> pub fn async_send<Req>(dispatch: Arc<EventDispatch>, request: Req) -> DispatchFuture<EventResponse>
where where
Req: std::convert::Into<ModuleRequest>, Req: std::convert::Into<ModuleRequest>,
{ {
EventDispatch::async_send_with_callback(request, |_| Box::pin(async {})) EventDispatch::async_send_with_callback(dispatch, request, |_| Box::pin(async {}))
} }
pub fn async_send_with_callback<Req, Callback>(request: Req, callback: Callback) -> DispatchFuture<EventResponse> pub fn async_send_with_callback<Req, Callback>(
dispatch: Arc<EventDispatch>,
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,
{ {
let request: ModuleRequest = request.into(); let request: ModuleRequest = request.into();
match EVENT_DISPATCH.read() { let module_map = dispatch.module_map.clone();
Ok(dispatch) => { let service = Box::new(DispatchService { module_map });
let dispatch = dispatch.as_ref().unwrap(); log::trace!("Async event: {:?}", &request.event);
let module_map = dispatch.module_map.clone(); let service_ctx = DispatchContext {
let service = Box::new(DispatchService { module_map }); request,
log::trace!("Async event: {:?}", &request.event); callback: Some(Box::new(callback)),
let service_ctx = DispatchContext { };
request, let join_handle = dispatch.runtime.spawn(async move {
callback: Some(Box::new(callback)), service
}; .call(service_ctx)
let join_handle = dispatch.runtime.spawn(async move { .await
service .unwrap_or_else(|e| InternalError::Other(format!("{:?}", e)).as_response())
.call(service_ctx) });
.await
.unwrap_or_else(|e| InternalError::Other(format!("{:?}", e)).as_response())
});
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!("EVENT_DISPATCH join error: {:?}", e)); let error = InternalError::JoinError(format!("EVENT_DISPATCH join error: {:?}", e));
error.as_response() error.as_response()
}) })
}), }),
}
},
Err(e) => {
let msg = format!("EVENT_DISPATCH read failed. {:?}", e);
DispatchFuture {
fut: Box::pin(async { InternalError::Lock(msg).as_response() }),
}
},
} }
// match dispatch.read() {
// Ok(dispatch) => {
// let dispatch = dispatch.as_ref().unwrap();
// let module_map = dispatch.module_map.clone();
// let service = Box::new(DispatchService { module_map });
// log::trace!("Async event: {:?}", &request.event);
// let service_ctx = DispatchContext {
// request,
// callback: Some(Box::new(callback)),
// };
// let join_handle = dispatch.runtime.spawn(async move {
// service
// .call(service_ctx)
// .await
// .unwrap_or_else(|e|
// InternalError::Other(format!("{:?}", e)).as_response())
// });
//
// DispatchFuture {
// fut: Box::pin(async move {
// join_handle.await.unwrap_or_else(|e| {
// let error =
// InternalError::JoinError(format!("EVENT_DISPATCH join error: {:?}",
// e)); error.as_response()
// })
// }),
// }
// },
//
// Err(e) => {
// let msg = format!("EVENT_DISPATCH read failed. {:?}", e);
// DispatchFuture {
// fut: Box::pin(async {
// InternalError::Lock(msg).as_response() }), }
// },
// }
} }
pub fn sync_send(request: ModuleRequest) -> EventResponse { pub fn sync_send(dispatch: Arc<EventDispatch>, 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(dispatch, request, |_| Box::pin(async {})).await })
} }
} }

View File

@ -16,17 +16,7 @@ use crate::{
module::{container::ModuleDataMap, Unit}, module::{container::ModuleDataMap, Unit},
request::{payload::Payload, EventRequest, FromRequest}, request::{payload::Payload, EventRequest, FromRequest},
response::{EventResponse, Responder}, response::{EventResponse, Responder},
service::{ service::{factory, BoxService, BoxServiceFactory, Handler, HandlerService, Service, ServiceFactory, ServiceRequest, ServiceResponse},
factory,
BoxService,
BoxServiceFactory,
Handler,
HandlerService,
Service,
ServiceFactory,
ServiceRequest,
ServiceResponse,
},
}; };
use futures_core::future::BoxFuture; use futures_core::future::BoxFuture;
use std::sync::Arc; use std::sync::Arc;
@ -51,8 +41,7 @@ impl<T: Display + Eq + Hash + Debug + Clone> std::convert::From<T> for Event {
fn from(t: T) -> Self { Event(format!("{}", t)) } fn from(t: T) -> Self { Event(format!("{}", t)) }
} }
pub type EventServiceFactory = pub type EventServiceFactory = BoxServiceFactory<(), ServiceRequest, ServiceResponse, DispatchError>;
BoxServiceFactory<(), ServiceRequest, ServiceResponse, DispatchError>;
pub struct Module { pub struct Module {
pub name: String, pub name: String,
@ -75,9 +64,7 @@ impl Module {
} }
pub fn data<D: 'static + Send + Sync>(mut self, data: D) -> Self { pub fn data<D: 'static + Send + Sync>(mut self, data: D) -> Self {
Arc::get_mut(&mut self.module_data) Arc::get_mut(&mut self.module_data).unwrap().insert(Unit::new(data));
.unwrap()
.insert(Unit::new(data));
self self
} }
@ -102,15 +89,10 @@ impl Module {
self self
} }
pub fn events(&self) -> Vec<Event> { pub fn events(&self) -> Vec<Event> { self.service_map.keys().map(|key| key.clone()).collect::<Vec<_>>() }
self.service_map
.keys()
.map(|key| key.clone())
.collect::<Vec<_>>()
}
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct ModuleRequest { pub struct ModuleRequest {
pub id: String, pub id: String,
pub event: Event, pub event: Event,
@ -139,9 +121,7 @@ impl ModuleRequest {
} }
impl std::fmt::Display for ModuleRequest { impl std::fmt::Display for ModuleRequest {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}:{:?}", self.id, self.event) }
write!(f, "{}:{:?}", self.id, self.event)
}
} }
impl ServiceFactory<ModuleRequest> for Module { impl ServiceFactory<ModuleRequest> for Module {
@ -155,10 +135,7 @@ impl ServiceFactory<ModuleRequest> for Module {
let service_map = self.service_map.clone(); let service_map = self.service_map.clone();
let module_data = self.module_data.clone(); let module_data = self.module_data.clone();
Box::pin(async move { Box::pin(async move {
let service = ModuleService { let service = ModuleService { service_map, module_data };
service_map,
module_data,
};
let module_service = Box::new(service) as Self::Service; let module_service = Box::new(service) as Self::Service;
Ok(module_service) Ok(module_service)
}) })
@ -193,10 +170,7 @@ impl Service<ModuleRequest> for ModuleService {
Box::pin(async move { Ok(fut.await.unwrap_or_else(|e| e.into())) }) Box::pin(async move { Ok(fut.await.unwrap_or_else(|e| e.into())) })
}, },
None => { None => {
let msg = format!( let msg = format!("Can not find service factory for event: {:?}", request.event);
"Can not find service factory for event: {:?}",
request.event
);
Box::pin(async { Err(InternalError::ServiceNotFound(msg).into()) }) Box::pin(async { Err(InternalError::ServiceNotFound(msg).into()) })
}, },
} }

View File

@ -10,9 +10,9 @@ pub fn setup_env() {
}); });
} }
pub fn init_dispatch<F>(module_factory: F) pub fn init_dispatch<F>(module_factory: F) -> EventDispatch
where where
F: FnOnce() -> Vec<Module>, F: FnOnce() -> Vec<Module>,
{ {
EventDispatch::construct(module_factory); EventDispatch::construct(module_factory)
} }

View File

@ -1,19 +1,21 @@
use crate::helper::*; use crate::helper::*;
use flowy_dispatch::prelude::*; use flowy_dispatch::prelude::*;
use std::sync::Arc;
pub async fn hello() -> String { "say hello".to_string() } pub async fn hello() -> String { "say hello".to_string() }
#[tokio::test] #[tokio::test]
async fn test_init() { async fn test() {
setup_env(); setup_env();
let event = "1"; let event = "1";
init_dispatch(|| vec![Module::new().event(event, hello)]); let dispatch = Arc::new(init_dispatch(|| vec![Module::new().event(event, hello)]));
let request = ModuleRequest::new(event); let request = ModuleRequest::new(event);
let _ = EventDispatch::async_send_with_callback(request, |resp| { let _ = EventDispatch::async_send_with_callback(dispatch.clone(), request, |resp| {
Box::pin(async move { Box::pin(async move {
dbg!(&resp); dbg!(&resp);
}) })
}) })
.await; .await;
std::mem::forget(dispatch);
} }

View File

@ -1,25 +1,25 @@
use crate::helper::*; use crate::helper::*;
use flowy_test::builder::UserTestBuilder; use flowy_test::TestSDKBuilder;
#[test] #[test]
fn file_create_test() { fn file_create_test() {
let _ = UserTestBuilder::new().sign_up(); let sdk = TestSDKBuilder::new().sign_up().build();
let doc_desc = create_doc("hello world", "flutter ❤️ rust", "123"); let doc_desc = create_doc(&sdk, "hello world", "flutter ❤️ rust", "123");
dbg!(&doc_desc); dbg!(&doc_desc);
let doc = read_doc_data(&doc_desc.id, &doc_desc.path); let doc = read_doc_data(&sdk, &doc_desc.id, &doc_desc.path);
assert_eq!(doc.text, "123".to_owned()); assert_eq!(doc.text, "123".to_owned());
} }
#[test] #[test]
fn file_update_text_test() { fn file_update_text_test() {
let _ = UserTestBuilder::new().sign_up(); let sdk = TestSDKBuilder::new().sign_up().build();
let doc_desc = create_doc("hello world", "flutter ❤️ rust", ""); let doc_desc = create_doc(&sdk, "hello world", "flutter ❤️ rust", "");
dbg!(&doc_desc); dbg!(&doc_desc);
let content = "😁😁😁😁😁😁😁😁😁😁".to_owned(); let content = "😁😁😁😁😁😁😁😁😁😁".to_owned();
save_doc(&doc_desc, &content); save_doc(&sdk, &doc_desc, &content);
let doc = read_doc_data(&doc_desc.id, &doc_desc.path); let doc = read_doc_data(&sdk, &doc_desc.id, &doc_desc.path);
assert_eq!(doc.text, content); assert_eq!(doc.text, content);
} }

View File

@ -2,8 +2,9 @@ use flowy_test::builder::DocTestBuilder;
use flowy_document::{entities::doc::*, event::EditorEvent::*}; use flowy_document::{entities::doc::*, event::EditorEvent::*};
use flowy_infra::uuid; use flowy_infra::uuid;
use flowy_test::prelude::*;
pub fn create_doc(name: &str, desc: &str, text: &str) -> DocInfo { pub fn create_doc(sdk: &FlowyTestSDK, name: &str, desc: &str, text: &str) -> DocInfo {
let request = CreateDocRequest { let request = CreateDocRequest {
id: uuid(), id: uuid(),
name: name.to_owned(), name: name.to_owned(),
@ -11,7 +12,7 @@ pub fn create_doc(name: &str, desc: &str, text: &str) -> DocInfo {
text: text.to_owned(), text: text.to_owned(),
}; };
let doc = DocTestBuilder::new() let doc = DocTestBuilder::new(sdk.clone())
.event(CreateDoc) .event(CreateDoc)
.request(request) .request(request)
.sync_send() .sync_send()
@ -19,7 +20,7 @@ pub fn create_doc(name: &str, desc: &str, text: &str) -> DocInfo {
doc doc
} }
pub fn save_doc(desc: &DocInfo, content: &str) { pub fn save_doc(sdk: &FlowyTestSDK, desc: &DocInfo, content: &str) {
let request = UpdateDocRequest { let request = UpdateDocRequest {
id: desc.id.clone(), id: desc.id.clone(),
name: Some(desc.name.clone()), name: Some(desc.name.clone()),
@ -27,7 +28,7 @@ pub fn save_doc(desc: &DocInfo, content: &str) {
text: Some(content.to_owned()), text: Some(content.to_owned()),
}; };
let _ = DocTestBuilder::new().event(UpdateDoc).request(request).sync_send(); let _ = DocTestBuilder::new(sdk.clone()).event(UpdateDoc).request(request).sync_send();
} }
// #[allow(dead_code)] // #[allow(dead_code)]
@ -45,13 +46,13 @@ pub fn save_doc(desc: &DocInfo, content: &str) {
// doc // doc
// } // }
pub(crate) fn read_doc_data(doc_id: &str, path: &str) -> DocData { pub(crate) fn read_doc_data(sdk: &FlowyTestSDK, 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 = DocTestBuilder::new() let doc = DocTestBuilder::new(sdk.clone())
.event(ReadDocData) .event(ReadDocData)
.request(request) .request(request)
.sync_send() .sync_send()

View File

@ -80,8 +80,7 @@ impl HttpRequestBuilder {
// reqwest client is not 'Sync' by channel is. // reqwest client is not 'Sync' by channel is.
tokio::spawn(async move { tokio::spawn(async move {
let client = default_client(); let client = default_client();
let mut builder = client.request(method, url).headers(headers); let mut builder = client.request(method.clone(), url).headers(headers);
if let Some(body) = body { if let Some(body) = body {
builder = builder.body(body); builder = builder.body(body);
} }
@ -90,7 +89,7 @@ impl HttpRequestBuilder {
match tx.send(response) { match tx.send(response) {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Send http response failed: {:?}", e) log::error!("[{}] Send http request failed: {:?}", method, e);
}, },
} }
}); });

View File

@ -7,8 +7,8 @@ edition = "2018"
[dependencies] [dependencies]
flowy-dispatch = { path = "../flowy-dispatch", features = ["use_tracing"]} flowy-dispatch = { path = "../flowy-dispatch", features = ["use_tracing"]}
#flowy-log = { path = "../flowy-log" } flowy-log = { path = "../flowy-log" }
flowy-log = { path = "../flowy-log", features = ["use_bunyan"] } #flowy-log = { path = "../flowy-log", features = ["use_bunyan"] }
flowy-user = { path = "../flowy-user" } flowy-user = { path = "../flowy-user" }
flowy-infra = { path = "../flowy-infra" } flowy-infra = { path = "../flowy-infra" }
flowy-workspace = { path = "../flowy-workspace" } flowy-workspace = { path = "../flowy-workspace" }

View File

@ -5,39 +5,49 @@ pub mod module;
use flowy_dispatch::prelude::*; use flowy_dispatch::prelude::*;
use module::build_modules; use module::build_modules;
pub use module::*; pub use module::*;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
static INIT_LOG: AtomicBool = AtomicBool::new(false); static INIT_LOG: AtomicBool = AtomicBool::new(false);
#[derive(Clone)]
pub struct FlowySDK { pub struct FlowySDK {
root: String, root: String,
dispatch: Arc<EventDispatch>,
} }
impl FlowySDK { impl FlowySDK {
pub fn new(root: &str) -> Self { Self { root: root.to_owned() } } pub fn new(root: &str) -> Self {
init_log(root);
init_kv(root);
pub fn construct(self) { FlowySDK::construct_with(&self.root) } let dispatch = Arc::new(init_dispatch(root));
let root = root.to_owned();
pub fn construct_with(root: &str) { Self { root, dispatch }
FlowySDK::init_log(root);
tracing::info!("🔥 Root path: {}", root);
match flowy_infra::kv::KV::init(root) {
Ok(_) => {},
Err(e) => tracing::error!("Init kv store failedL: {}", e),
}
FlowySDK::init_modules(root);
} }
fn init_log(directory: &str) { pub fn dispatch(&self) -> Arc<EventDispatch> { self.dispatch.clone() }
if !INIT_LOG.load(Ordering::SeqCst) { }
INIT_LOG.store(true, Ordering::SeqCst);
let _ = flowy_log::Builder::new("flowy").local(directory).env_filter("info").build(); fn init_kv(root: &str) {
} tracing::info!("🔥 Root path: {}", root);
} match flowy_infra::kv::KV::init(root) {
Ok(_) => {},
fn init_modules(root: &str) { Err(e) => tracing::error!("Init kv store failedL: {}", e),
let config = ModuleConfig { root: root.to_owned() };
EventDispatch::construct(|| build_modules(config));
} }
} }
fn init_log(directory: &str) {
if !INIT_LOG.load(Ordering::SeqCst) {
INIT_LOG.store(true, Ordering::SeqCst);
let _ = flowy_log::Builder::new("flowy").local(directory).env_filter("info").build();
}
}
fn init_dispatch(root: &str) -> EventDispatch {
let config = ModuleConfig { root: root.to_owned() };
let dispatch = EventDispatch::construct(|| build_modules(config));
dispatch
}

View File

@ -1,137 +1,190 @@
use flowy_dispatch::prelude::{FromBytes, ToBytes}; use flowy_dispatch::prelude::{EventDispatch, EventResponse, FromBytes, ModuleRequest, StatusCode, ToBytes};
use flowy_user::entities::UserDetail; use flowy_user::entities::UserDetail;
use std::{ use std::{
fmt::{Debug, Display}, fmt::{Debug, Display},
hash::Hash, hash::Hash,
}; };
use crate::{ use crate::helper::{create_default_workspace_if_need, login_email, login_password, random_email};
helper::{create_default_workspace_if_need, login_email, login_password}, use flowy_dispatch::prelude::*;
init_test_sdk,
tester::{TesterContext, TesterTrait},
};
use flowy_document::errors::DocError; use flowy_document::errors::DocError;
use flowy_user::errors::UserError; pub use flowy_sdk::*;
use flowy_user::{
errors::UserError,
event::UserEvent::{SignOut, SignUp},
prelude::*,
};
use flowy_workspace::errors::WorkspaceError; use flowy_workspace::errors::WorkspaceError;
use std::marker::PhantomData; use std::{marker::PhantomData, sync::Arc};
pub type WorkspaceTestBuilder = Builder<RandomUserTester<WorkspaceError>>; use crate::FlowyTestSDK;
impl WorkspaceTestBuilder { use flowy_user::event::UserEvent::SignIn;
pub fn new() -> Self { Builder::test(Box::new(RandomUserTester::<WorkspaceError>::new())) } use std::convert::TryFrom;
}
pub type DocTestBuilder = Builder<RandomUserTester<DocError>>; pub type DocTestBuilder = Builder<DocError>;
impl DocTestBuilder { impl DocTestBuilder {
pub fn new() -> Self { Builder::test(Box::new(RandomUserTester::<DocError>::new())) } pub fn new(sdk: FlowyTestSDK) -> Self { Builder::test(TestContext::new(sdk)) }
} }
pub type UserTestBuilder = Builder<RandomUserTester<UserError>>; pub type WorkspaceTestBuilder = Builder<WorkspaceError>;
impl UserTestBuilder { impl WorkspaceTestBuilder {
pub fn new() -> Self { Builder::test(Box::new(RandomUserTester::<UserError>::new())) } pub fn new(sdk: FlowyTestSDK) -> Self { Builder::test(TestContext::new(sdk)) }
}
pub fn sign_up(mut self) -> SignUpContext { pub type UserTestBuilder = Builder<UserError>;
let (user_detail, password) = self.tester.sign_up(); impl UserTestBuilder {
let _ = create_default_workspace_if_need(&user_detail.id); pub fn new(sdk: FlowyTestSDK) -> Self { Builder::test(TestContext::new(sdk)) }
pub fn sign_up(self) -> SignUpContext {
let password = login_password();
let payload = SignUpRequest {
email: random_email(),
name: "app flowy".to_string(),
password: password.clone(),
}
.into_bytes()
.unwrap();
let request = ModuleRequest::new(SignUp).payload(payload);
let user_detail = EventDispatch::sync_send(self.dispatch(), request)
.parse::<UserDetail, UserError>()
.unwrap()
.unwrap();
let _ = create_default_workspace_if_need(self.dispatch(), &user_detail.id);
SignUpContext { user_detail, password } SignUpContext { user_detail, password }
} }
pub fn sign_in(mut self) -> Self { #[allow(dead_code)]
let user_detail = self.tester.sign_in(); fn sign_in(mut self) -> Self {
let payload = SignInRequest {
email: login_email(),
password: login_password(),
}
.into_bytes()
.unwrap();
let request = ModuleRequest::new(SignIn).payload(payload);
let user_detail = EventDispatch::sync_send(self.dispatch(), request)
.parse::<UserDetail, UserError>()
.unwrap()
.unwrap();
self.user_detail = Some(user_detail); self.user_detail = Some(user_detail);
self self
} }
fn login_if_need(&mut self) { #[allow(dead_code)]
let user_detail = self.tester.login_if_need(); fn logout(&self) { let _ = EventDispatch::sync_send(self.dispatch(), ModuleRequest::new(SignOut)); }
self.user_detail = Some(user_detail);
}
pub fn get_user_detail(&self) -> &Option<UserDetail> { &self.user_detail } pub fn user_detail(&self) -> &Option<UserDetail> { &self.user_detail }
} }
pub struct Builder<T: TesterTrait> { #[derive(Clone)]
pub tester: Box<T>, pub struct Builder<E> {
context: TestContext,
user_detail: Option<UserDetail>, user_detail: Option<UserDetail>,
err_phantom: PhantomData<E>,
} }
impl<T> Builder<T> impl<E> Builder<E>
where where
T: TesterTrait, E: FromBytes + Debug,
{ {
fn test(tester: Box<T>) -> Self { pub(crate) fn test(context: TestContext) -> Self {
init_test_sdk(); Self {
Self { tester, user_detail: None } context,
user_detail: None,
err_phantom: PhantomData,
}
} }
pub fn request<P>(mut self, request: P) -> Self pub fn request<P>(mut self, payload: P) -> Self
where where
P: ToBytes, P: ToBytes,
{ {
self.tester.set_payload(request); match payload.into_bytes() {
Ok(bytes) => {
let module_request = self.get_request();
self.context.request = Some(module_request.payload(bytes))
},
Err(e) => {
log::error!("Set payload failed: {:?}", e);
},
}
self self
} }
pub fn event<E>(mut self, event: E) -> Self pub fn event<Event>(mut self, event: Event) -> Self
where where
E: Eq + Hash + Debug + Clone + Display, Event: Eq + Hash + Debug + Clone + Display,
{ {
self.tester.set_event(event); self.context.request = Some(ModuleRequest::new(event));
self self
} }
pub fn sync_send(mut self) -> Self { pub fn sync_send(mut self) -> Self {
self.tester.sync_send(); let request = self.get_request();
let resp = EventDispatch::sync_send(self.dispatch(), request);
self.context.response = Some(resp);
self self
} }
pub fn parse<R>(mut self) -> R pub fn parse<R>(self) -> R
where where
R: FromBytes, R: FromBytes,
{ {
self.tester.parse::<R>() let response = self.get_response();
match response.parse::<R, E>() {
Ok(Ok(data)) => data,
Ok(Err(e)) => {
panic!("parse failed: {:?}", e)
},
Err(e) => panic!("Internal error: {:?}", e),
}
} }
pub fn error(mut self) -> <T as TesterTrait>::Error { self.tester.error() } pub fn error(self) -> E {
let response = self.get_response();
assert_eq!(response.status_code, StatusCode::Err);
<Data<E>>::try_from(response.payload).unwrap().into_inner()
}
pub fn assert_error(mut self) -> Self { pub fn assert_error(self) -> Self {
self.tester.assert_error(); // self.context.assert_error();
self self
} }
pub fn assert_success(mut self) -> Self { pub fn assert_success(self) -> Self {
self.tester.assert_success(); // self.context.assert_success();
self self
} }
pub fn sdk(&self) -> FlowySDK { self.context.sdk.clone() }
fn dispatch(&self) -> Arc<EventDispatch> { self.context.sdk.dispatch() }
fn get_response(&self) -> EventResponse { self.context.response.as_ref().expect("must call sync_send first").clone() }
fn get_request(&mut self) -> ModuleRequest { self.context.request.take().expect("must call event first") }
} }
pub struct RandomUserTester<Error> { #[derive(Clone)]
context: TesterContext, pub struct TestContext {
err_phantom: PhantomData<Error>, sdk: FlowyTestSDK,
request: Option<ModuleRequest>,
response: Option<EventResponse>,
} }
impl<Error> RandomUserTester<Error> impl TestContext {
where pub fn new(sdk: FlowyTestSDK) -> Self {
Error: FromBytes + Debug,
{
pub fn new() -> Self {
Self { Self {
context: TesterContext::default(), sdk,
err_phantom: PhantomData, request: None,
response: None,
} }
} }
} }
impl<Error> TesterTrait for RandomUserTester<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,

View File

@ -1,13 +1,14 @@
use bytes::Bytes; use bytes::Bytes;
use flowy_dispatch::prelude::{DispatchError, EventDispatch, ModuleRequest, ToBytes}; use flowy_dispatch::prelude::{EventDispatch, ModuleRequest, ToBytes};
use flowy_infra::{kv::KV, uuid}; 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, errors::WorkspaceError,
event::WorkspaceEvent::{CreateWorkspace, OpenWorkspace}, event::WorkspaceEvent::{CreateWorkspace, OpenWorkspace},
}; };
use std::{fs, path::PathBuf}; use std::{fs, path::PathBuf, sync::Arc};
pub fn root_dir() -> String { pub fn root_dir() -> String {
// https://doc.rust-lang.org/cargo/reference/environment-variables.html // https://doc.rust-lang.org/cargo/reference/environment-variables.html
@ -35,7 +36,7 @@ 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";
const DEFAULT_WORKSPACE: &'static str = "Default_Workspace"; const DEFAULT_WORKSPACE: &'static str = "Default_Workspace";
pub(crate) fn create_default_workspace_if_need(user_id: &str) -> Result<(), UserError> { pub(crate) fn create_default_workspace_if_need(dispatch: Arc<EventDispatch>, user_id: &str) -> Result<(), UserError> {
let key = format!("{}{}", user_id, DEFAULT_WORKSPACE); let key = format!("{}{}", user_id, DEFAULT_WORKSPACE);
if KV::get_bool(&key).unwrap_or(false) { if KV::get_bool(&key).unwrap_or(false) {
return Err(ErrorBuilder::new(ErrorCode::DefaultWorkspaceAlreadyExist).build()); return Err(ErrorBuilder::new(ErrorCode::DefaultWorkspaceAlreadyExist).build());
@ -50,12 +51,11 @@ pub(crate) fn create_default_workspace_if_need(user_id: &str) -> Result<(), User
.unwrap(); .unwrap();
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(dispatch.clone(), request)
.parse::<Workspace, WorkspaceError>() .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())?;
let query: Bytes = QueryWorkspaceRequest { let query: Bytes = QueryWorkspaceRequest {
workspace_id: Some(workspace.id.clone()), workspace_id: Some(workspace.id.clone()),
} }
@ -63,7 +63,7 @@ pub(crate) fn create_default_workspace_if_need(user_id: &str) -> Result<(), User
.unwrap(); .unwrap();
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(dispatch.clone(), request)
.parse::<Workspace, WorkspaceError>() .parse::<Workspace, WorkspaceError>()
.unwrap() .unwrap()
.unwrap(); .unwrap();

View File

@ -1,21 +1,34 @@
pub mod builder; pub mod builder;
mod helper; mod helper;
mod tester; // pub mod workspace_builder;
use crate::helper::root_dir; use crate::{builder::UserTestBuilder, helper::root_dir};
use flowy_sdk::FlowySDK; use flowy_sdk::FlowySDK;
use std::sync::Once;
pub mod prelude { pub mod prelude {
pub use crate::{builder::*, helper::*}; pub use crate::{builder::*, helper::*, *};
pub use flowy_dispatch::prelude::*; pub use flowy_dispatch::prelude::*;
} }
static INIT: Once = Once::new(); pub type FlowyTestSDK = FlowySDK;
pub fn init_test_sdk() {
let root_dir = root_dir();
INIT.call_once(|| { #[derive(Clone)]
FlowySDK::construct_with(&root_dir); pub struct TestSDKBuilder {
}); inner: FlowyTestSDK,
}
impl TestSDKBuilder {
pub fn new() -> Self { Self { inner: init_test_sdk() } }
pub fn sign_up(self) -> Self {
let _ = UserTestBuilder::new(self.inner.clone()).sign_up();
self
}
pub fn build(self) -> FlowyTestSDK { self.inner }
}
pub fn init_test_sdk() -> FlowyTestSDK {
let root_dir = root_dir();
FlowySDK::new(&root_dir)
} }

View File

@ -1,142 +0,0 @@
use crate::{
helper::{login_password, random_email},
init_test_sdk,
};
use flowy_dispatch::prelude::*;
pub use flowy_sdk::*;
use flowy_user::{
errors::UserError,
event::UserEvent::{GetUserProfile, SignOut, SignUp},
prelude::*,
};
use crate::helper::login_email;
use flowy_user::event::UserEvent::SignIn;
use std::{
convert::TryFrom,
fmt::{Debug, Display},
hash::Hash,
};
#[allow(dead_code)]
pub struct TesterContext {
request: Option<ModuleRequest>,
response: Option<EventResponse>,
status_code: StatusCode,
}
impl TesterContext {
pub fn new(email: String) -> Self { TesterContext::default() }
}
impl std::default::Default for TesterContext {
fn default() -> Self {
Self {
request: None,
status_code: StatusCode::Ok,
response: None,
}
}
}
pub trait TesterTrait {
type Error: FromBytes + Debug;
fn mut_context(&mut self) -> &mut TesterContext;
fn context(&self) -> &TesterContext;
fn assert_error(&mut self) { self.mut_context().status_code = StatusCode::Err; }
fn assert_success(&mut self) { self.mut_context().status_code = StatusCode::Ok; }
fn set_event<E>(&mut self, event: E)
where
E: Eq + Hash + Debug + Clone + Display,
{
self.mut_context().request = Some(ModuleRequest::new(event));
}
fn set_payload<P>(&mut self, payload: P)
where
P: ToBytes,
{
match payload.into_bytes() {
Ok(bytes) => {
let module_request = self.mut_context().request.take().unwrap();
self.mut_context().request = Some(module_request.payload(bytes));
},
Err(e) => {
log::error!("Set payload failed: {:?}", e);
},
}
}
fn sync_send(&mut self) {
let resp = EventDispatch::sync_send(self.mut_context().request.take().unwrap());
self.mut_context().response = Some(resp);
}
// TODO: support return Option<R>
fn parse<R>(&mut self) -> R
where
R: FromBytes,
{
let response = self.mut_context().response.clone().unwrap();
match response.parse::<R, Self::Error>() {
Ok(Ok(data)) => data,
Ok(Err(e)) => {
panic!("parse failed: {:?}", e)
},
Err(e) => panic!("Internal error: {:?}", e),
}
}
fn error(&mut self) -> Self::Error {
let response = self.mut_context().response.clone().unwrap();
assert_eq!(response.status_code, StatusCode::Err);
<Data<Self::Error>>::try_from(response.payload).unwrap().into_inner()
}
fn sign_up(&self) -> (UserDetail, String) {
let password = login_password();
let payload = SignUpRequest {
email: login_email(),
name: "app flowy".to_string(),
password: password.clone(),
}
.into_bytes()
.unwrap();
let request = ModuleRequest::new(SignUp).payload(payload);
let user_detail = EventDispatch::sync_send(request).parse::<UserDetail, UserError>().unwrap().unwrap();
(user_detail, password)
}
fn sign_in(&self) -> UserDetail {
let payload = SignInRequest {
email: login_email(),
password: login_password(),
}
.into_bytes()
.unwrap();
let request = ModuleRequest::new(SignIn).payload(payload);
let user_detail = EventDispatch::sync_send(request).parse::<UserDetail, UserError>().unwrap().unwrap();
user_detail
}
fn login_if_need(&self) -> UserDetail {
match EventDispatch::sync_send(ModuleRequest::new(GetUserProfile))
.parse::<UserDetail, UserError>()
.unwrap()
{
Ok(user_detail) => user_detail,
Err(_e) => self.sign_in(),
}
}
fn logout(&self) { let _ = EventDispatch::sync_send(ModuleRequest::new(SignOut)); }
}

View File

@ -0,0 +1,60 @@
use super::builder::Builder;
use crate::{builder::TestContext, helper::FlowyTestSDK};
use flowy_workspace::{
entities::{app::App, view::View, workspace::*},
errors::WorkspaceError,
event::WorkspaceEvent::*,
};
pub enum WorkspaceAction {
CreateWorkspace(CreateWorkspaceRequest),
ReadWorkspace(QueryWorkspaceRequest),
}
type Inner = Builder<WorkspaceError>;
pub struct WorkspaceTestBuilder {
workspace: Option<Workspace>,
app: Option<App>,
view: Option<View>,
inner: Builder<WorkspaceError>,
}
impl WorkspaceTestBuilder {
pub fn new(sdk: FlowyTestSDK) -> Self {
Self {
workspace: None,
app: None,
view: None,
inner: Builder::test(TestContext::new(sdk)),
}
}
pub fn run(mut self, actions: Vec<WorkspaceAction>) {
let inner = self.inner;
for action in actions {
match action {
WorkspaceAction::CreateWorkspace(request) => {
let workspace = inner
.clone()
.event(CreateWorkspace)
.request(request)
.sync_send()
.parse::<Workspace>();
self.workspace = Some(workspace);
},
WorkspaceAction::ReadWorkspace(request) => {
let mut repeated_workspace = inner
.clone()
.event(ReadWorkspaces)
.request(request)
.sync_send()
.parse::<RepeatedWorkspace>();
debug_assert_eq!(repeated_workspace.len(), 1, "Default workspace not found");
repeated_workspace.drain(..1).collect::<Vec<Workspace>>().pop()
},
}
}
}
}

View File

@ -49,4 +49,4 @@ futures = "0.3.15"
serial_test = "0.5.1" serial_test = "0.5.1"
[features] [features]
mock_server = [] http_server = []

View File

@ -17,7 +17,7 @@ impl std::default::Default for UserStatus {
fn default() -> Self { UserStatus::Unknown } fn default() -> Self { UserStatus::Unknown }
} }
#[derive(ProtoBuf, Default, Debug, PartialEq, Eq)] #[derive(ProtoBuf, Default, Debug, PartialEq, Eq, Clone)]
pub struct UserDetail { pub struct UserDetail {
#[pb(index = 1)] #[pb(index = 1)]
pub id: String, pub id: String,
@ -135,36 +135,19 @@ impl TryInto<UpdateUserParams> for UpdateUserRequest {
let name = match self.name { let name = match self.name {
None => None, None => None,
Some(name) => Some( Some(name) => Some(UserName::parse(name).map_err(|e| ErrorBuilder::new(e).build())?.0),
UserName::parse(name)
.map_err(|e| ErrorBuilder::new(e).build())?
.0,
),
}; };
let email = match self.email { let email = match self.email {
None => None, None => None,
Some(email) => Some( Some(email) => Some(UserEmail::parse(email).map_err(|e| ErrorBuilder::new(e).build())?.0),
UserEmail::parse(email)
.map_err(|e| ErrorBuilder::new(e).build())?
.0,
),
}; };
let password = match self.password { let password = match self.password {
None => None, None => None,
Some(password) => Some( Some(password) => Some(UserPassword::parse(password).map_err(|e| ErrorBuilder::new(e).build())?.0),
UserPassword::parse(password)
.map_err(|e| ErrorBuilder::new(e).build())?
.0,
),
}; };
Ok(UpdateUserParams { Ok(UpdateUserParams { id, name, email, password })
id,
name,
email,
password,
})
} }
} }

View File

@ -20,9 +20,9 @@ pub trait UserServerAPI {
} }
pub(crate) fn construct_user_server() -> Arc<dyn UserServerAPI + Send + Sync> { pub(crate) fn construct_user_server() -> Arc<dyn UserServerAPI + Send + Sync> {
if cfg!(feature = "mock_server") { if cfg!(feature = "http_server") {
Arc::new(UserServerMock {})
} else {
Arc::new(UserServer {}) Arc::new(UserServer {})
} else {
Arc::new(UserServerMock {})
} }
} }

View File

@ -3,7 +3,7 @@ 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::{lock_api::RwLockReadGuard, Mutex, RawRwLock, RwLock}; use parking_lot::{Mutex, RwLock};
use std::{collections::HashMap, sync::Arc, time::Duration}; use std::{collections::HashMap, sync::Arc, time::Duration};
lazy_static! { lazy_static! {
static ref DB: RwLock<Option<Database>> = RwLock::new(None); static ref DB: RwLock<Option<Database>> = RwLock::new(None);

View File

@ -170,7 +170,7 @@ impl UserSession {
} }
fn set_session(&self, session: Option<Session>) -> Result<(), UserError> { fn set_session(&self, session: Option<Session>) -> Result<(), UserError> {
log::trace!("Update user session: {:?}", session); log::debug!("Update user session: {:?}", session);
match &session { match &session {
None => KV::remove(SESSION_CACHE_KEY).map_err(|e| UserError::new(ErrorCode::SqlInternalError, &e))?, None => KV::remove(SESSION_CACHE_KEY).map_err(|e| UserError::new(ErrorCode::SqlInternalError, &e))?,
Some(session) => KV::set_str(SESSION_CACHE_KEY, session.clone().into()), Some(session) => KV::set_str(SESSION_CACHE_KEY, session.clone().into()),

View File

@ -1,19 +1,13 @@
use crate::helper::*; use crate::helper::*;
use flowy_test::builder::UserTestBuilder; use flowy_test::{builder::UserTestBuilder, init_test_sdk};
use flowy_user::{errors::ErrorCode, event::UserEvent::*, prelude::*}; use flowy_user::{errors::ErrorCode, event::UserEvent::*, prelude::*};
use serial_test::*; use serial_test::*;
#[test]
#[serial]
fn sign_up_success() {
let user_detail = UserTestBuilder::new().sign_up().user_detail;
log::info!("{:?}", user_detail);
}
#[test] #[test]
#[serial] #[serial]
fn sign_up_with_invalid_email() { fn sign_up_with_invalid_email() {
for email in invalid_email_test_case() { for email in invalid_email_test_case() {
let sdk = init_test_sdk();
let request = SignUpRequest { let request = SignUpRequest {
email: email.to_string(), email: email.to_string(),
name: valid_name(), name: valid_name(),
@ -21,7 +15,7 @@ fn sign_up_with_invalid_email() {
}; };
assert_eq!( assert_eq!(
UserTestBuilder::new().event(SignUp).request(request).sync_send().error().code, UserTestBuilder::new(sdk).event(SignUp).request(request).sync_send().error().code,
ErrorCode::EmailFormatInvalid ErrorCode::EmailFormatInvalid
); );
} }
@ -30,28 +24,30 @@ fn sign_up_with_invalid_email() {
#[serial] #[serial]
fn sign_up_with_invalid_password() { fn sign_up_with_invalid_password() {
for password in invalid_password_test_case() { for password in invalid_password_test_case() {
let sdk = init_test_sdk();
let request = SignUpRequest { let request = SignUpRequest {
email: random_email(), email: random_email(),
name: valid_name(), name: valid_name(),
password, password,
}; };
UserTestBuilder::new().event(SignUp).request(request).sync_send().assert_error(); UserTestBuilder::new(sdk).event(SignUp).request(request).sync_send().assert_error();
} }
} }
#[test] #[test]
#[serial] #[serial]
fn sign_in_success() { fn sign_in_success() {
let context = UserTestBuilder::new().sign_up(); let sdk = init_test_sdk();
let _ = UserTestBuilder::new().event(SignOut).sync_send(); let context = UserTestBuilder::new(sdk.clone()).sign_up();
let _ = UserTestBuilder::new(sdk.clone()).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 = UserTestBuilder::new() let response = UserTestBuilder::new(sdk)
.event(SignIn) .event(SignIn)
.request(request) .request(request)
.sync_send() .sync_send()
@ -63,13 +59,14 @@ fn sign_in_success() {
#[serial] #[serial]
fn sign_in_with_invalid_email() { fn sign_in_with_invalid_email() {
for email in invalid_email_test_case() { for email in invalid_email_test_case() {
let sdk = init_test_sdk();
let request = SignInRequest { let request = SignInRequest {
email: email.to_string(), email: email.to_string(),
password: login_password(), password: login_password(),
}; };
assert_eq!( assert_eq!(
UserTestBuilder::new().event(SignIn).request(request).sync_send().error().code, UserTestBuilder::new(sdk).event(SignIn).request(request).sync_send().error().code,
ErrorCode::EmailFormatInvalid ErrorCode::EmailFormatInvalid
); );
} }
@ -79,11 +76,12 @@ fn sign_in_with_invalid_email() {
#[serial] #[serial]
fn sign_in_with_invalid_password() { fn sign_in_with_invalid_password() {
for password in invalid_password_test_case() { for password in invalid_password_test_case() {
let sdk = init_test_sdk();
let request = SignInRequest { let request = SignInRequest {
email: random_email(), email: random_email(),
password, password,
}; };
UserTestBuilder::new().event(SignIn).request(request).sync_send().assert_error(); UserTestBuilder::new(sdk).event(SignIn).request(request).sync_send().assert_error();
} }
} }

View File

@ -1,22 +1,24 @@
use crate::helper::*; use crate::helper::*;
use flowy_infra::uuid; use flowy_infra::uuid;
use flowy_test::builder::UserTestBuilder; use flowy_test::{builder::UserTestBuilder, init_test_sdk};
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_profile_get_failed() {
let tester = UserTestBuilder::new().event(GetUserProfile).assert_error().sync_send(); let sdk = init_test_sdk();
assert!(tester.get_user_detail().is_none()) let result = UserTestBuilder::new(sdk).event(GetUserProfile).assert_error().sync_send();
assert!(result.user_detail().is_none())
} }
#[test] #[test]
#[serial] #[serial]
fn user_detail_get() { fn user_profile_get() {
let user_detail = UserTestBuilder::new().sign_up().user_detail; let sdk = init_test_sdk();
let user_detail = UserTestBuilder::new(sdk.clone()).sign_up().user_detail;
let user_detail2 = UserTestBuilder::new().event(GetUserProfile).sync_send().parse::<UserDetail>(); let user_detail2 = UserTestBuilder::new(sdk).event(GetUserProfile).sync_send().parse::<UserDetail>();
assert_eq!(user_detail, user_detail2); assert_eq!(user_detail, user_detail2);
} }
@ -24,12 +26,13 @@ fn user_detail_get() {
#[test] #[test]
#[serial] #[serial]
fn user_update_with_name() { fn user_update_with_name() {
let user_detail = UserTestBuilder::new().sign_up().user_detail; let sdk = init_test_sdk();
let user_detail = UserTestBuilder::new(sdk.clone()).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 _ = UserTestBuilder::new().event(UpdateUser).request(request).sync_send(); let _ = UserTestBuilder::new(sdk.clone()).event(UpdateUser).request(request).sync_send();
let user_detail = UserTestBuilder::new() let user_detail = UserTestBuilder::new(sdk)
.event(GetUserProfile) .event(GetUserProfile)
.assert_error() .assert_error()
.sync_send() .sync_send()
@ -41,13 +44,14 @@ fn user_update_with_name() {
#[test] #[test]
#[serial] #[serial]
fn user_update_with_email() { fn user_update_with_email() {
let user_detail = UserTestBuilder::new().sign_up().user_detail; let sdk = init_test_sdk();
let user_detail = UserTestBuilder::new(sdk.clone()).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 _ = UserTestBuilder::new().event(UpdateUser).request(request).sync_send(); let _ = UserTestBuilder::new(sdk.clone()).event(UpdateUser).request(request).sync_send();
let user_detail = UserTestBuilder::new() let user_detail = UserTestBuilder::new(sdk)
.event(GetUserProfile) .event(GetUserProfile)
.assert_error() .assert_error()
.sync_send() .sync_send()
@ -59,11 +63,12 @@ fn user_update_with_email() {
#[test] #[test]
#[serial] #[serial]
fn user_update_with_password() { fn user_update_with_password() {
let user_detail = UserTestBuilder::new().sign_up().user_detail; let sdk = init_test_sdk();
let user_detail = UserTestBuilder::new(sdk.clone()).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 _ = UserTestBuilder::new() let _ = UserTestBuilder::new(sdk)
.event(UpdateUser) .event(UpdateUser)
.request(request) .request(request)
.sync_send() .sync_send()
@ -73,11 +78,17 @@ fn user_update_with_password() {
#[test] #[test]
#[serial] #[serial]
fn user_update_with_invalid_email() { fn user_update_with_invalid_email() {
let user_detail = UserTestBuilder::new().sign_up().user_detail; let sdk = init_test_sdk();
let user_detail = UserTestBuilder::new(sdk.clone()).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!(
UserTestBuilder::new().event(UpdateUser).request(request).sync_send().error().code, UserTestBuilder::new(sdk.clone())
.event(UpdateUser)
.request(request)
.sync_send()
.error()
.code,
ErrorCode::EmailFormatInvalid ErrorCode::EmailFormatInvalid
); );
} }
@ -86,19 +97,29 @@ 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 = UserTestBuilder::new().sign_up().user_detail; let sdk = init_test_sdk();
let user_detail = UserTestBuilder::new(sdk.clone()).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);
UserTestBuilder::new().event(UpdateUser).request(request).sync_send().assert_error(); UserTestBuilder::new(sdk.clone())
.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 = UserTestBuilder::new().sign_up().user_detail; let sdk = init_test_sdk();
let user_detail = UserTestBuilder::new(sdk.clone()).sign_up().user_detail;
let request = UpdateUserRequest::new(&user_detail.id).name(""); let request = UpdateUserRequest::new(&user_detail.id).name("");
UserTestBuilder::new().event(UpdateUser).request(request).sync_send().assert_error(); UserTestBuilder::new(sdk)
.event(UpdateUser)
.request(request)
.sync_send()
.assert_error();
} }

View File

@ -37,4 +37,4 @@ serial_test = "0.5.1"
[features] [features]
mock_server = [] http_server = []

View File

@ -1,8 +1,4 @@
use crate::{ use crate::{entities::workspace::*, errors::WorkspaceError, services::WorkspaceController};
entities::workspace::*,
errors::{ErrorBuilder, ErrorCode, WorkspaceError},
services::WorkspaceController,
};
use flowy_dispatch::prelude::{data_result, Data, DataResult, Unit}; use flowy_dispatch::prelude::{data_result, Data, DataResult, Unit};
use std::{convert::TryInto, sync::Arc}; use std::{convert::TryInto, sync::Arc};

View File

@ -51,9 +51,9 @@ pub trait WorkspaceServerAPI {
} }
pub(crate) fn construct_workspace_server() -> Arc<dyn WorkspaceServerAPI + Send + Sync> { pub(crate) fn construct_workspace_server() -> Arc<dyn WorkspaceServerAPI + Send + Sync> {
if cfg!(feature = "mock_server") { if cfg!(feature = "http_server") {
Arc::new(WorkspaceServerMock {})
} else {
Arc::new(WorkspaceServer {}) Arc::new(WorkspaceServer {})
} else {
Arc::new(WorkspaceServerMock {})
} }
} }

View File

@ -6,7 +6,7 @@ use crate::{
services::{helper::spawn, server::Server, AppController}, services::{helper::spawn, server::Server, AppController},
sql_tables::workspace::{WorkspaceSql, WorkspaceTable, WorkspaceTableChangeset}, sql_tables::workspace::{WorkspaceSql, WorkspaceTable, WorkspaceTableChangeset},
}; };
use flowy_dispatch::prelude::DispatchFuture;
use flowy_infra::kv::KV; use flowy_infra::kv::KV;
use std::sync::Arc; use std::sync::Arc;

View File

@ -1,6 +1,6 @@
use crate::helper::*; use crate::helper::*;
use flowy_test::prelude::*;
use flowy_test::builder::UserTestBuilder;
use flowy_workspace::entities::{ use flowy_workspace::entities::{
app::{QueryAppRequest, UpdateAppRequest}, app::{QueryAppRequest, UpdateAppRequest},
view::*, view::*,
@ -8,40 +8,39 @@ use flowy_workspace::entities::{
#[test] #[test]
fn app_create() { fn app_create() {
let _ = UserTestBuilder::new().sign_up(); let sdk = TestSDKBuilder::new().sign_up().build();
let workspace = create_workspace("Workspace", ""); let workspace = create_workspace(&sdk, "Workspace", "");
let app = create_app("App A", "AppFlowy Github Project", &workspace.id); let app = create_app(&sdk, "App A", "AppFlowy Github Project", &workspace.id);
dbg!(&app); dbg!(&app);
} }
#[test] #[test]
#[should_panic] #[should_panic]
fn app_delete() { fn app_delete() {
let _ = UserTestBuilder::new().sign_up(); let sdk = TestSDKBuilder::new().sign_up().build();
let workspace = create_workspace(&sdk, "Workspace", "");
let workspace = create_workspace("Workspace", ""); let app = create_app(&sdk, "App A", "AppFlowy Github Project", &workspace.id);
let app = create_app("App A", "AppFlowy Github Project", &workspace.id); delete_app(&sdk, &app.id);
delete_app(&app.id);
let query = QueryAppRequest::new(&app.id); let query = QueryAppRequest::new(&app.id);
let _ = read_app(query); let _ = read_app(&sdk, query);
} }
#[test] #[test]
fn app_read() { fn app_read() {
let _ = UserTestBuilder::new().sign_up(); let sdk = TestSDKBuilder::new().sign_up().build();
let workspace = create_workspace("Workspace", ""); let workspace = create_workspace(&sdk, "Workspace", "");
let app = create_app("App A", "AppFlowy Github Project", &workspace.id); let app = create_app(&sdk, "App A", "AppFlowy Github Project", &workspace.id);
let query = QueryAppRequest::new(&app.id); let query = QueryAppRequest::new(&app.id);
let app_from_db = read_app(query); let app_from_db = read_app(&sdk, query);
assert_eq!(app_from_db, app); assert_eq!(app_from_db, app);
} }
#[test] #[test]
fn app_create_with_view() { fn app_create_with_view() {
let _a = UserTestBuilder::new().sign_up(); let sdk = TestSDKBuilder::new().sign_up().build();
let workspace = create_workspace("Workspace", ""); let workspace = create_workspace(&sdk, "Workspace", "");
let app = create_app("App A", "AppFlowy Github Project", &workspace.id); let app = create_app(&sdk, "App A", "AppFlowy Github Project", &workspace.id);
let request_a = CreateViewRequest { let request_a = CreateViewRequest {
belong_to_id: app.id.clone(), belong_to_id: app.id.clone(),
name: "View A".to_string(), name: "View A".to_string(),
@ -58,11 +57,11 @@ fn app_create_with_view() {
view_type: ViewType::Doc, view_type: ViewType::Doc,
}; };
let view_a = create_view_with_request(request_a); let view_a = create_view_with_request(&sdk, request_a);
let view_b = create_view_with_request(request_b); let view_b = create_view_with_request(&sdk, request_b);
let query = QueryAppRequest::new(&app.id).set_read_views(true); let query = QueryAppRequest::new(&app.id).set_read_views(true);
let view_from_db = read_app(query); let view_from_db = read_app(&sdk, query);
assert_eq!(view_from_db.belongings[0], view_a); assert_eq!(view_from_db.belongings[0], view_a);
assert_eq!(view_from_db.belongings[1], view_b); assert_eq!(view_from_db.belongings[1], view_b);
@ -70,24 +69,24 @@ fn app_create_with_view() {
#[test] #[test]
fn app_set_trash_flag() { fn app_set_trash_flag() {
let _ = UserTestBuilder::new().sign_up(); let sdk = TestSDKBuilder::new().sign_up().build();
let app_id = create_app_with_trash_flag(); let app_id = create_app_with_trash_flag(&sdk);
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(&sdk, query);
} }
#[test] #[test]
#[should_panic] #[should_panic]
fn app_set_trash_flag_2() { fn app_set_trash_flag_2() {
let _ = UserTestBuilder::new().sign_up(); let sdk = TestSDKBuilder::new().sign_up().build();
let app_id = create_app_with_trash_flag(); let app_id = create_app_with_trash_flag(&sdk);
let query = QueryAppRequest::new(&app_id); let query = QueryAppRequest::new(&app_id);
let _ = read_app(query); let _ = read_app(&sdk, query);
} }
fn create_app_with_trash_flag() -> String { fn create_app_with_trash_flag(sdk: &FlowyTestSDK) -> String {
let workspace = create_workspace("Workspace", ""); let workspace = create_workspace(sdk, "Workspace", "");
let app = create_app("App A", "AppFlowy Github Project", &workspace.id); let app = create_app(sdk, "App A", "AppFlowy Github Project", &workspace.id);
let request = UpdateAppRequest { let request = UpdateAppRequest {
app_id: app.id.clone(), app_id: app.id.clone(),
name: None, name: None,
@ -95,7 +94,7 @@ fn create_app_with_trash_flag() -> String {
color_style: None, color_style: None,
is_trash: Some(true), is_trash: Some(true),
}; };
update_app(request); update_app(sdk, request);
app.id app.id
} }

View File

@ -1,4 +1,4 @@
use flowy_test::builder::{UserTestBuilder, WorkspaceTestBuilder}; use flowy_test::prelude::*;
use flowy_workspace::{ use flowy_workspace::{
entities::{app::*, view::*, workspace::*}, entities::{app::*, view::*, workspace::*},
event::WorkspaceEvent::*, event::WorkspaceEvent::*,
@ -11,13 +11,13 @@ pub(crate) fn invalid_workspace_name_test_case() -> Vec<String> {
.collect::<Vec<_>>() .collect::<Vec<_>>()
} }
pub fn create_workspace(name: &str, desc: &str) -> Workspace { pub fn create_workspace(sdk: &FlowyTestSDK, name: &str, desc: &str) -> Workspace {
let request = CreateWorkspaceRequest { let request = CreateWorkspaceRequest {
name: name.to_owned(), name: name.to_owned(),
desc: desc.to_owned(), desc: desc.to_owned(),
}; };
let workspace = WorkspaceTestBuilder::new() let workspace = WorkspaceTestBuilder::new(sdk.clone())
.event(CreateWorkspace) .event(CreateWorkspace)
.request(request) .request(request)
.sync_send() .sync_send()
@ -25,8 +25,8 @@ pub fn create_workspace(name: &str, desc: &str) -> Workspace {
workspace workspace
} }
pub fn read_workspaces(request: QueryWorkspaceRequest) -> Option<Workspace> { pub fn read_workspaces(sdk: &FlowyTestSDK, request: QueryWorkspaceRequest) -> Option<Workspace> {
let mut repeated_workspace = WorkspaceTestBuilder::new() let mut repeated_workspace = WorkspaceTestBuilder::new(sdk.clone())
.event(ReadWorkspaces) .event(ReadWorkspaces)
.request(request) .request(request)
.sync_send() .sync_send()
@ -36,7 +36,7 @@ pub fn read_workspaces(request: QueryWorkspaceRequest) -> Option<Workspace> {
repeated_workspace.drain(..1).collect::<Vec<Workspace>>().pop() repeated_workspace.drain(..1).collect::<Vec<Workspace>>().pop()
} }
pub fn create_app(name: &str, desc: &str, workspace_id: &str) -> App { pub fn create_app(sdk: &FlowyTestSDK, name: &str, desc: &str, workspace_id: &str) -> App {
let create_app_request = CreateAppRequest { let create_app_request = CreateAppRequest {
workspace_id: workspace_id.to_owned(), workspace_id: workspace_id.to_owned(),
name: name.to_string(), name: name.to_string(),
@ -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 = WorkspaceTestBuilder::new() let app = WorkspaceTestBuilder::new(sdk.clone())
.event(CreateApp) .event(CreateApp)
.request(create_app_request) .request(create_app_request)
.sync_send() .sync_send()
@ -52,18 +52,23 @@ pub fn create_app(name: &str, desc: &str, workspace_id: &str) -> App {
app app
} }
pub fn delete_app(app_id: &str) { pub fn delete_app(sdk: &FlowyTestSDK, app_id: &str) {
let delete_app_request = DeleteAppRequest { let delete_app_request = DeleteAppRequest {
app_id: app_id.to_string(), app_id: app_id.to_string(),
}; };
WorkspaceTestBuilder::new().event(DeleteApp).request(delete_app_request).sync_send(); WorkspaceTestBuilder::new(sdk.clone())
.event(DeleteApp)
.request(delete_app_request)
.sync_send();
} }
pub fn update_app(request: UpdateAppRequest) { WorkspaceTestBuilder::new().event(UpdateApp).request(request).sync_send(); } pub fn update_app(sdk: &FlowyTestSDK, request: UpdateAppRequest) {
WorkspaceTestBuilder::new(sdk.clone()).event(UpdateApp).request(request).sync_send();
}
pub fn read_app(request: QueryAppRequest) -> App { pub fn read_app(sdk: &FlowyTestSDK, request: QueryAppRequest) -> App {
let app = WorkspaceTestBuilder::new() let app = WorkspaceTestBuilder::new(sdk.clone())
.event(ReadApp) .event(ReadApp)
.request(request) .request(request)
.sync_send() .sync_send()
@ -72,8 +77,8 @@ pub fn read_app(request: QueryAppRequest) -> App {
app app
} }
pub fn create_view_with_request(request: CreateViewRequest) -> View { pub fn create_view_with_request(sdk: &FlowyTestSDK, request: CreateViewRequest) -> View {
let view = WorkspaceTestBuilder::new() let view = WorkspaceTestBuilder::new(sdk.clone())
.event(CreateView) .event(CreateView)
.request(request) .request(request)
.sync_send() .sync_send()
@ -82,8 +87,8 @@ pub fn create_view_with_request(request: CreateViewRequest) -> View {
view view
} }
pub fn create_view(workspace_id: &str) -> View { pub fn create_view(sdk: &FlowyTestSDK, workspace_id: &str) -> View {
let app = create_app("App A", "AppFlowy Github Project", workspace_id); let app = create_app(sdk, "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,13 +97,18 @@ pub fn create_view(workspace_id: &str) -> View {
view_type: ViewType::Doc, view_type: ViewType::Doc,
}; };
create_view_with_request(request) create_view_with_request(sdk, request)
} }
pub fn update_view(request: UpdateViewRequest) { WorkspaceTestBuilder::new().event(UpdateView).request(request).sync_send(); } pub fn update_view(sdk: &FlowyTestSDK, request: UpdateViewRequest) {
WorkspaceTestBuilder::new(sdk.clone())
.event(UpdateView)
.request(request)
.sync_send();
}
pub fn read_view(request: QueryViewRequest) -> View { pub fn read_view(sdk: &FlowyTestSDK, request: QueryViewRequest) -> View {
WorkspaceTestBuilder::new() WorkspaceTestBuilder::new(sdk.clone())
.event(ReadView) .event(ReadView)
.request(request) .request(request)
.sync_send() .sync_send()

View File

@ -1,37 +1,36 @@
use crate::helper::*; use crate::helper::*;
use flowy_test::builder::UserTestBuilder; use flowy_test::{FlowyTestSDK, TestSDKBuilder};
use flowy_workspace::entities::view::*; use flowy_workspace::entities::view::*;
#[test] #[test]
fn view_create() { fn view_create() {
let _ = UserTestBuilder::new().sign_up(); let sdk = TestSDKBuilder::new().sign_up().build();
let workspace = create_workspace(&sdk, "Workspace", "");
let workspace = create_workspace("Workspace", ""); let _ = create_view(&sdk, &workspace.id);
let _ = create_view(&workspace.id);
} }
#[test] #[test]
fn view_set_trash_flag() { fn view_set_trash_flag() {
let _ = UserTestBuilder::new().sign_up(); let sdk = TestSDKBuilder::new().sign_up().build();
let view_id = create_view_with_trash_flag(); let view_id = create_view_with_trash_flag(&sdk);
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(&sdk, query);
} }
#[test] #[test]
#[should_panic] #[should_panic]
fn view_set_trash_flag2() { fn view_set_trash_flag2() {
let _ = UserTestBuilder::new().sign_up(); let sdk = TestSDKBuilder::new().sign_up().build();
let view_id = create_view_with_trash_flag(); let view_id = create_view_with_trash_flag(&sdk);
let query = QueryViewRequest::new(&view_id); let query = QueryViewRequest::new(&view_id);
let _ = read_view(query); let _ = read_view(&sdk, query);
} }
fn create_view_with_trash_flag() -> String { fn create_view_with_trash_flag(sdk: &FlowyTestSDK) -> String {
let workspace = create_workspace("Workspace", ""); let workspace = create_workspace(sdk, "Workspace", "");
let view = create_view(&workspace.id); let view = create_view(sdk, &workspace.id);
let request = UpdateViewRequest { let request = UpdateViewRequest {
view_id: view.id.clone(), view_id: view.id.clone(),
name: None, name: None,
@ -39,7 +38,7 @@ fn create_view_with_trash_flag() -> String {
thumbnail: None, thumbnail: None,
is_trash: Some(true), is_trash: Some(true),
}; };
update_view(request); update_view(sdk, request);
view.id view.id
} }

View File

@ -1,5 +1,5 @@
use crate::helper::*; use crate::helper::*;
use flowy_test::builder::*; use flowy_test::{builder::*, TestSDKBuilder};
use flowy_workspace::{ use flowy_workspace::{
entities::workspace::{CreateWorkspaceRequest, QueryWorkspaceRequest, RepeatedWorkspace}, entities::workspace::{CreateWorkspaceRequest, QueryWorkspaceRequest, RepeatedWorkspace},
event::WorkspaceEvent::*, event::WorkspaceEvent::*,
@ -7,14 +7,17 @@ use flowy_workspace::{
}; };
#[test] #[test]
fn workspace_create_success() { let _ = create_workspace("First workspace", ""); } fn workspace_create_success() {
let sdk = TestSDKBuilder::new().sign_up().build();
let _ = create_workspace(&sdk, "First workspace", "");
}
#[test] #[test]
fn workspace_read_all() { fn workspace_read_all() {
let _ = UserTestBuilder::new().sign_up(); let sdk = TestSDKBuilder::new().sign_up().build();
let _ = create_workspace("Workspace A", "workspace_create_and_then_get_workspace_success"); let _ = create_workspace(&sdk, "Workspace A", "workspace_create_and_then_get_workspace_success");
let workspaces = WorkspaceTestBuilder::new() let workspaces = WorkspaceTestBuilder::new(sdk.clone())
.event(ReadWorkspaces) .event(ReadWorkspaces)
.request(QueryWorkspaceRequest::new()) .request(QueryWorkspaceRequest::new())
.sync_send() .sync_send()
@ -25,29 +28,32 @@ fn workspace_read_all() {
#[test] #[test]
fn workspace_create_and_then_get_workspace() { fn workspace_create_and_then_get_workspace() {
let workspace = create_workspace("Workspace A", "workspace_create_and_then_get_workspace_success"); let sdk = TestSDKBuilder::new().sign_up().build();
let workspace = create_workspace(&sdk, "Workspace A", "workspace_create_and_then_get_workspace_success");
let request = QueryWorkspaceRequest::new().workspace_id(&workspace.id); let request = QueryWorkspaceRequest::new().workspace_id(&workspace.id);
let workspace_from_db = read_workspaces(request).unwrap(); let workspace_from_db = read_workspaces(&sdk, request).unwrap();
assert_eq!(workspace.name, workspace_from_db.name); assert_eq!(workspace.name, workspace_from_db.name);
} }
#[test] #[test]
fn workspace_create_with_apps() { fn workspace_create_with_apps() {
let workspace = create_workspace("Workspace", ""); let sdk = TestSDKBuilder::new().sign_up().build();
let app = create_app("App A", "AppFlowy Github Project", &workspace.id); let workspace = create_workspace(&sdk, "Workspace", "");
let app = create_app(&sdk, "App A", "AppFlowy Github Project", &workspace.id);
let request = QueryWorkspaceRequest::new().workspace_id(&workspace.id); let request = QueryWorkspaceRequest::new().workspace_id(&workspace.id);
let workspace_from_db = read_workspaces(request).unwrap(); let workspace_from_db = read_workspaces(&sdk, request).unwrap();
assert_eq!(&app, workspace_from_db.apps.first_or_crash()); assert_eq!(&app, workspace_from_db.apps.first_or_crash());
} }
#[test] #[test]
fn workspace_create_with_invalid_name() { fn workspace_create_with_invalid_name() {
let sdk = TestSDKBuilder::new().sign_up().build();
for name in invalid_workspace_name_test_case() { for name in invalid_workspace_name_test_case() {
let _ = UserTestBuilder::new().sign_up(); let _ = UserTestBuilder::new(sdk.clone()).sign_up();
let request = CreateWorkspaceRequest { name, desc: "".to_owned() }; let request = CreateWorkspaceRequest { name, desc: "".to_owned() };
assert_eq!( assert_eq!(
WorkspaceTestBuilder::new() WorkspaceTestBuilder::new(sdk.clone())
.event(CreateWorkspace) .event(CreateWorkspace)
.request(request) .request(request)
.sync_send() .sync_send()
@ -60,11 +66,11 @@ 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(); let sdk = TestSDKBuilder::new().sign_up().build();
for name in invalid_workspace_name_test_case() { for name in invalid_workspace_name_test_case() {
let request = CreateWorkspaceRequest { name, desc: "".to_owned() }; let request = CreateWorkspaceRequest { name, desc: "".to_owned() };
assert_eq!( assert_eq!(
WorkspaceTestBuilder::new() WorkspaceTestBuilder::new(sdk.clone())
.event(CreateWorkspace) .event(CreateWorkspace)
.request(request) .request(request)
.sync_send() .sync_send()

View File

@ -5,16 +5,15 @@ dependencies = ["rm_cache"]
description = "Build desktop targets." description = "Build desktop targets."
script = ''' script = '''
cd rust-lib cd rust-lib
cargo test --features "flowy-workspace/mock_server","flowy-user/mock_server" cargo test
''' '''
[tasks.test_remote] [tasks.test_remote]
dependencies = ["rm_cache", "run_server"] dependencies = ["rm_cache"]
[tasks.run_test_remote_command]
script = """ script = """
cd rust-lib cd rust-lib
cargo test cargo test --features "flowy-workspace/http_server","flowy-user/http_server"
""" """