From ccb51234c5abccb408b997e661fe3b03ab1eed66 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sat, 4 Sep 2021 15:12:53 +0800 Subject: [PATCH] support run tests on remote --- rust-lib/dart-ffi/Cargo.toml | 1 + rust-lib/dart-ffi/src/lib.rs | 22 +- rust-lib/flowy-dispatch/src/dispatch.rs | 115 ++++++----- rust-lib/flowy-dispatch/src/module/module.rs | 42 +--- rust-lib/flowy-dispatch/tests/api/helper.rs | 4 +- rust-lib/flowy-dispatch/tests/api/module.rs | 10 +- .../flowy-document/tests/editor/doc_test.rs | 16 +- .../flowy-document/tests/editor/helper.rs | 13 +- rust-lib/flowy-net/src/request/request.rs | 5 +- rust-lib/flowy-sdk/Cargo.toml | 4 +- rust-lib/flowy-sdk/src/lib.rs | 56 ++--- rust-lib/flowy-test/src/builder.rs | 191 +++++++++++------- rust-lib/flowy-test/src/helper.rs | 12 +- rust-lib/flowy-test/src/lib.rs | 33 ++- rust-lib/flowy-test/src/tester.rs | 142 ------------- rust-lib/flowy-test/src/workspace_builder.rs | 60 ++++++ rust-lib/flowy-user/Cargo.toml | 2 +- .../flowy-user/src/entities/user_detail.rs | 27 +-- .../flowy-user/src/services/server/mod.rs | 6 +- .../flowy-user/src/services/user/database.rs | 2 +- .../src/services/user/user_session.rs | 2 +- rust-lib/flowy-user/tests/event/auth_test.rs | 28 ++- .../tests/event/user_profile_test.rs | 63 ++++-- rust-lib/flowy-workspace/Cargo.toml | 2 +- .../src/handlers/workspace_handler.rs | 6 +- .../src/services/server/mod.rs | 6 +- .../src/services/workspace_controller.rs | 2 +- .../tests/workspace/app_test.rs | 59 +++--- .../flowy-workspace/tests/workspace/helper.rs | 50 +++-- .../tests/workspace/view_test.rs | 29 ++- .../tests/workspace/workspace_test.rs | 34 ++-- scripts/makefile/tests.toml | 7 +- 32 files changed, 529 insertions(+), 522 deletions(-) delete mode 100644 rust-lib/flowy-test/src/tester.rs create mode 100644 rust-lib/flowy-test/src/workspace_builder.rs diff --git a/rust-lib/dart-ffi/Cargo.toml b/rust-lib/dart-ffi/Cargo.toml index 3132ea54aa..a0279e37eb 100644 --- a/rust-lib/dart-ffi/Cargo.toml +++ b/rust-lib/dart-ffi/Cargo.toml @@ -25,6 +25,7 @@ log = "0.4.14" serde = { version = "1.0", features = ["derive"] } serde_json = {version = "1.0"} bytes = { version = "1.0" } +parking_lot = "0.11" flowy-dispatch = {path = "../flowy-dispatch"} flowy-sdk = {path = "../flowy-sdk"} diff --git a/rust-lib/dart-ffi/src/lib.rs b/rust-lib/dart-ffi/src/lib.rs index 03122f7519..03ce33e826 100644 --- a/rust-lib/dart-ffi/src/lib.rs +++ b/rust-lib/dart-ffi/src/lib.rs @@ -9,15 +9,22 @@ use crate::{ }; use flowy_dispatch::prelude::*; 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>> = RwLock::new(None); +} + +fn dispatch() -> Arc { FLOWY_SDK.read().as_ref().unwrap().dispatch() } #[no_mangle] pub extern "C" fn init_sdk(path: *mut c_char) -> i64 { let c_str: &CStr = unsafe { CStr::from_ptr(path) }; let path: &str = c_str.to_str().unwrap(); log::info!("🔥 FlowySDK start running"); - FlowySDK::new(path).construct(); + *FLOWY_SDK.write() = Some(Arc::new(FlowySDK::new(path))); return 1; } @@ -25,14 +32,9 @@ pub extern "C" fn init_sdk(path: *mut c_char) -> i64 { #[no_mangle] pub extern "C" fn async_command(port: i64, input: *const u8, len: usize) { let request: ModuleRequest = FFIRequest::from_u8_pointer(input, len).into(); - log::trace!( - "[FFI]: {} Async Event: {:?} with {} port", - &request.id, - &request.event, - port - ); + log::trace!("[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); 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 { let request: ModuleRequest = FFIRequest::from_u8_pointer(input, len).into(); log::trace!("[FFI]: {} Sync Event: {:?}", &request.id, &request.event,); - let _response = EventDispatch::sync_send(request); + let _response = EventDispatch::sync_send(dispatch(), request); // FFIResponse { } let response_bytes = vec![]; diff --git a/rust-lib/flowy-dispatch/src/dispatch.rs b/rust-lib/flowy-dispatch/src/dispatch.rs index 49d24f5693..f6b9a5cfe8 100644 --- a/rust-lib/flowy-dispatch/src/dispatch.rs +++ b/rust-lib/flowy-dispatch/src/dispatch.rs @@ -8,22 +8,17 @@ use crate::{ use derivative::*; use futures_core::future::BoxFuture; use futures_util::task::Context; -use lazy_static::lazy_static; + use pin_project::pin_project; -use std::{future::Future, sync::RwLock}; +use std::{future::Future, sync::Arc}; use tokio::macros::support::{Pin, Poll}; - -lazy_static! { - static ref EVENT_DISPATCH: RwLock> = RwLock::new(None); -} - pub struct EventDispatch { module_map: ModuleMap, runtime: tokio::runtime::Runtime, } impl EventDispatch { - pub fn construct(module_factory: F) + pub fn construct(module_factory: F) -> EventDispatch where F: FnOnce() -> Vec, { @@ -32,60 +27,88 @@ impl EventDispatch { let module_map = as_module_map(modules); let runtime = tokio_default_runtime().unwrap(); let dispatch = EventDispatch { module_map, runtime }; - *(EVENT_DISPATCH.write().unwrap()) = Some(dispatch); + dispatch } - pub fn async_send(request: Req) -> DispatchFuture + pub fn async_send(dispatch: Arc, request: Req) -> DispatchFuture where Req: std::convert::Into, { - 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(request: Req, callback: Callback) -> DispatchFuture + pub fn async_send_with_callback( + dispatch: Arc, + request: Req, + callback: Callback, + ) -> DispatchFuture where Req: std::convert::Into, Callback: FnOnce(EventResponse) -> BoxFuture<'static, ()> + 'static + Send + Sync, { let request: ModuleRequest = request.into(); - match EVENT_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()) - }); + 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() }), - } - }, + 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() + }) + }), } + // 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 { - futures::executor::block_on(async { EventDispatch::async_send_with_callback(request, |_| Box::pin(async {})).await }) + pub fn sync_send(dispatch: Arc, request: ModuleRequest) -> EventResponse { + futures::executor::block_on(async { EventDispatch::async_send_with_callback(dispatch, request, |_| Box::pin(async {})).await }) } } diff --git a/rust-lib/flowy-dispatch/src/module/module.rs b/rust-lib/flowy-dispatch/src/module/module.rs index e0893be7e5..7998578269 100644 --- a/rust-lib/flowy-dispatch/src/module/module.rs +++ b/rust-lib/flowy-dispatch/src/module/module.rs @@ -16,17 +16,7 @@ use crate::{ module::{container::ModuleDataMap, Unit}, request::{payload::Payload, EventRequest, FromRequest}, response::{EventResponse, Responder}, - service::{ - factory, - BoxService, - BoxServiceFactory, - Handler, - HandlerService, - Service, - ServiceFactory, - ServiceRequest, - ServiceResponse, - }, + service::{factory, BoxService, BoxServiceFactory, Handler, HandlerService, Service, ServiceFactory, ServiceRequest, ServiceResponse}, }; use futures_core::future::BoxFuture; use std::sync::Arc; @@ -51,8 +41,7 @@ impl std::convert::From for Event { fn from(t: T) -> Self { Event(format!("{}", t)) } } -pub type EventServiceFactory = - BoxServiceFactory<(), ServiceRequest, ServiceResponse, DispatchError>; +pub type EventServiceFactory = BoxServiceFactory<(), ServiceRequest, ServiceResponse, DispatchError>; pub struct Module { pub name: String, @@ -75,9 +64,7 @@ impl Module { } pub fn data(mut self, data: D) -> Self { - Arc::get_mut(&mut self.module_data) - .unwrap() - .insert(Unit::new(data)); + Arc::get_mut(&mut self.module_data).unwrap().insert(Unit::new(data)); self } @@ -102,15 +89,10 @@ impl Module { self } - pub fn events(&self) -> Vec { - self.service_map - .keys() - .map(|key| key.clone()) - .collect::>() - } + pub fn events(&self) -> Vec { self.service_map.keys().map(|key| key.clone()).collect::>() } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ModuleRequest { pub id: String, pub event: Event, @@ -139,9 +121,7 @@ impl ModuleRequest { } impl std::fmt::Display for ModuleRequest { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}:{:?}", self.id, self.event) - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}:{:?}", self.id, self.event) } } impl ServiceFactory for Module { @@ -155,10 +135,7 @@ impl ServiceFactory for Module { let service_map = self.service_map.clone(); let module_data = self.module_data.clone(); Box::pin(async move { - let service = ModuleService { - service_map, - module_data, - }; + let service = ModuleService { service_map, module_data }; let module_service = Box::new(service) as Self::Service; Ok(module_service) }) @@ -193,10 +170,7 @@ impl Service for ModuleService { Box::pin(async move { Ok(fut.await.unwrap_or_else(|e| e.into())) }) }, None => { - let msg = format!( - "Can not find service factory for event: {:?}", - request.event - ); + let msg = format!("Can not find service factory for event: {:?}", request.event); Box::pin(async { Err(InternalError::ServiceNotFound(msg).into()) }) }, } diff --git a/rust-lib/flowy-dispatch/tests/api/helper.rs b/rust-lib/flowy-dispatch/tests/api/helper.rs index 63f5ae2125..c2a8127550 100644 --- a/rust-lib/flowy-dispatch/tests/api/helper.rs +++ b/rust-lib/flowy-dispatch/tests/api/helper.rs @@ -10,9 +10,9 @@ pub fn setup_env() { }); } -pub fn init_dispatch(module_factory: F) +pub fn init_dispatch(module_factory: F) -> EventDispatch where F: FnOnce() -> Vec, { - EventDispatch::construct(module_factory); + EventDispatch::construct(module_factory) } diff --git a/rust-lib/flowy-dispatch/tests/api/module.rs b/rust-lib/flowy-dispatch/tests/api/module.rs index 65d1b12a52..db4508517c 100644 --- a/rust-lib/flowy-dispatch/tests/api/module.rs +++ b/rust-lib/flowy-dispatch/tests/api/module.rs @@ -1,19 +1,21 @@ use crate::helper::*; use flowy_dispatch::prelude::*; +use std::sync::Arc; pub async fn hello() -> String { "say hello".to_string() } #[tokio::test] -async fn test_init() { +async fn test() { setup_env(); 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 _ = EventDispatch::async_send_with_callback(request, |resp| { + let _ = EventDispatch::async_send_with_callback(dispatch.clone(), request, |resp| { Box::pin(async move { dbg!(&resp); }) }) .await; + + std::mem::forget(dispatch); } diff --git a/rust-lib/flowy-document/tests/editor/doc_test.rs b/rust-lib/flowy-document/tests/editor/doc_test.rs index 494d3804e6..adbc18ad4d 100644 --- a/rust-lib/flowy-document/tests/editor/doc_test.rs +++ b/rust-lib/flowy-document/tests/editor/doc_test.rs @@ -1,25 +1,25 @@ use crate::helper::*; -use flowy_test::builder::UserTestBuilder; +use flowy_test::TestSDKBuilder; #[test] fn file_create_test() { - let _ = UserTestBuilder::new().sign_up(); - let doc_desc = create_doc("hello world", "flutter ❤️ rust", "123"); + let sdk = TestSDKBuilder::new().sign_up().build(); + let doc_desc = create_doc(&sdk, "hello world", "flutter ❤️ rust", "123"); 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()); } #[test] fn file_update_text_test() { - let _ = UserTestBuilder::new().sign_up(); - let doc_desc = create_doc("hello world", "flutter ❤️ rust", ""); + let sdk = TestSDKBuilder::new().sign_up().build(); + let doc_desc = create_doc(&sdk, "hello world", "flutter ❤️ rust", ""); dbg!(&doc_desc); 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); } diff --git a/rust-lib/flowy-document/tests/editor/helper.rs b/rust-lib/flowy-document/tests/editor/helper.rs index 04f27f799e..c7ab5bf940 100644 --- a/rust-lib/flowy-document/tests/editor/helper.rs +++ b/rust-lib/flowy-document/tests/editor/helper.rs @@ -2,8 +2,9 @@ use flowy_test::builder::DocTestBuilder; use flowy_document::{entities::doc::*, event::EditorEvent::*}; 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 { id: uuid(), name: name.to_owned(), @@ -11,7 +12,7 @@ pub fn create_doc(name: &str, desc: &str, text: &str) -> DocInfo { text: text.to_owned(), }; - let doc = DocTestBuilder::new() + let doc = DocTestBuilder::new(sdk.clone()) .event(CreateDoc) .request(request) .sync_send() @@ -19,7 +20,7 @@ pub fn create_doc(name: &str, desc: &str, text: &str) -> DocInfo { doc } -pub fn save_doc(desc: &DocInfo, content: &str) { +pub fn save_doc(sdk: &FlowyTestSDK, desc: &DocInfo, content: &str) { let request = UpdateDocRequest { id: desc.id.clone(), name: Some(desc.name.clone()), @@ -27,7 +28,7 @@ pub fn save_doc(desc: &DocInfo, content: &str) { 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)] @@ -45,13 +46,13 @@ pub fn save_doc(desc: &DocInfo, content: &str) { // 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 { doc_id: doc_id.to_string(), path: path.to_string(), }; - let doc = DocTestBuilder::new() + let doc = DocTestBuilder::new(sdk.clone()) .event(ReadDocData) .request(request) .sync_send() diff --git a/rust-lib/flowy-net/src/request/request.rs b/rust-lib/flowy-net/src/request/request.rs index b02a492958..84ee84f2ab 100644 --- a/rust-lib/flowy-net/src/request/request.rs +++ b/rust-lib/flowy-net/src/request/request.rs @@ -80,8 +80,7 @@ impl HttpRequestBuilder { // reqwest client is not 'Sync' by channel is. tokio::spawn(async move { 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 { builder = builder.body(body); } @@ -90,7 +89,7 @@ impl HttpRequestBuilder { match tx.send(response) { Ok(_) => {}, Err(e) => { - log::error!("Send http response failed: {:?}", e) + log::error!("[{}] Send http request failed: {:?}", method, e); }, } }); diff --git a/rust-lib/flowy-sdk/Cargo.toml b/rust-lib/flowy-sdk/Cargo.toml index e2cbc2c717..20171b36d0 100644 --- a/rust-lib/flowy-sdk/Cargo.toml +++ b/rust-lib/flowy-sdk/Cargo.toml @@ -7,8 +7,8 @@ edition = "2018" [dependencies] flowy-dispatch = { path = "../flowy-dispatch", features = ["use_tracing"]} -#flowy-log = { path = "../flowy-log" } -flowy-log = { path = "../flowy-log", features = ["use_bunyan"] } +flowy-log = { path = "../flowy-log" } +#flowy-log = { path = "../flowy-log", features = ["use_bunyan"] } flowy-user = { path = "../flowy-user" } flowy-infra = { path = "../flowy-infra" } flowy-workspace = { path = "../flowy-workspace" } diff --git a/rust-lib/flowy-sdk/src/lib.rs b/rust-lib/flowy-sdk/src/lib.rs index c20106a874..c637fbb06e 100644 --- a/rust-lib/flowy-sdk/src/lib.rs +++ b/rust-lib/flowy-sdk/src/lib.rs @@ -5,39 +5,49 @@ pub mod module; use flowy_dispatch::prelude::*; use module::build_modules; pub use module::*; -use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{ + atomic::{AtomicBool, Ordering}, + Arc, +}; static INIT_LOG: AtomicBool = AtomicBool::new(false); +#[derive(Clone)] pub struct FlowySDK { root: String, + dispatch: Arc, } 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) } - - pub fn construct_with(root: &str) { - 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); + let dispatch = Arc::new(init_dispatch(root)); + let root = root.to_owned(); + Self { root, dispatch } } - fn init_log(directory: &str) { - if !INIT_LOG.load(Ordering::SeqCst) { - INIT_LOG.store(true, Ordering::SeqCst); + pub fn dispatch(&self) -> Arc { self.dispatch.clone() } +} - let _ = flowy_log::Builder::new("flowy").local(directory).env_filter("info").build(); - } - } - - fn init_modules(root: &str) { - let config = ModuleConfig { root: root.to_owned() }; - EventDispatch::construct(|| build_modules(config)); +fn init_kv(root: &str) { + tracing::info!("🔥 Root path: {}", root); + match flowy_infra::kv::KV::init(root) { + Ok(_) => {}, + Err(e) => tracing::error!("Init kv store failedL: {}", e), } } + +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 +} diff --git a/rust-lib/flowy-test/src/builder.rs b/rust-lib/flowy-test/src/builder.rs index 62c7e7c61a..764efad199 100644 --- a/rust-lib/flowy-test/src/builder.rs +++ b/rust-lib/flowy-test/src/builder.rs @@ -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 std::{ fmt::{Debug, Display}, hash::Hash, }; -use crate::{ - helper::{create_default_workspace_if_need, login_email, login_password}, - init_test_sdk, - tester::{TesterContext, TesterTrait}, -}; +use crate::helper::{create_default_workspace_if_need, login_email, login_password, random_email}; +use flowy_dispatch::prelude::*; 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 std::marker::PhantomData; +use std::{marker::PhantomData, sync::Arc}; -pub type WorkspaceTestBuilder = Builder>; -impl WorkspaceTestBuilder { - pub fn new() -> Self { Builder::test(Box::new(RandomUserTester::::new())) } -} +use crate::FlowyTestSDK; +use flowy_user::event::UserEvent::SignIn; +use std::convert::TryFrom; -pub type DocTestBuilder = Builder>; +pub type DocTestBuilder = Builder; impl DocTestBuilder { - pub fn new() -> Self { Builder::test(Box::new(RandomUserTester::::new())) } + pub fn new(sdk: FlowyTestSDK) -> Self { Builder::test(TestContext::new(sdk)) } } -pub type UserTestBuilder = Builder>; -impl UserTestBuilder { - pub fn new() -> Self { Builder::test(Box::new(RandomUserTester::::new())) } +pub type WorkspaceTestBuilder = Builder; +impl WorkspaceTestBuilder { + pub fn new(sdk: FlowyTestSDK) -> Self { Builder::test(TestContext::new(sdk)) } +} - pub fn sign_up(mut self) -> SignUpContext { - let (user_detail, password) = self.tester.sign_up(); - let _ = create_default_workspace_if_need(&user_detail.id); +pub type UserTestBuilder = Builder; +impl UserTestBuilder { + 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::() + .unwrap() + .unwrap(); + + let _ = create_default_workspace_if_need(self.dispatch(), &user_detail.id); SignUpContext { user_detail, password } } - pub fn sign_in(mut self) -> Self { - let user_detail = self.tester.sign_in(); + #[allow(dead_code)] + 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::() + .unwrap() + .unwrap(); + self.user_detail = Some(user_detail); self } - fn login_if_need(&mut self) { - let user_detail = self.tester.login_if_need(); - self.user_detail = Some(user_detail); - } + #[allow(dead_code)] + fn logout(&self) { let _ = EventDispatch::sync_send(self.dispatch(), ModuleRequest::new(SignOut)); } - pub fn get_user_detail(&self) -> &Option { &self.user_detail } + pub fn user_detail(&self) -> &Option { &self.user_detail } } -pub struct Builder { - pub tester: Box, +#[derive(Clone)] +pub struct Builder { + context: TestContext, user_detail: Option, + err_phantom: PhantomData, } -impl Builder +impl Builder where - T: TesterTrait, + E: FromBytes + Debug, { - fn test(tester: Box) -> Self { - init_test_sdk(); - Self { tester, user_detail: None } + pub(crate) fn test(context: TestContext) -> Self { + Self { + context, + user_detail: None, + err_phantom: PhantomData, + } } - pub fn request

(mut self, request: P) -> Self + pub fn request

(mut self, payload: P) -> Self where 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 } - pub fn event(mut self, event: E) -> Self + pub fn event(mut self, event: Event) -> Self 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 } 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 } - pub fn parse(mut self) -> R + pub fn parse(self) -> R where R: FromBytes, { - self.tester.parse::() + let response = self.get_response(); + match response.parse::() { + Ok(Ok(data)) => data, + Ok(Err(e)) => { + panic!("parse failed: {:?}", e) + }, + Err(e) => panic!("Internal error: {:?}", e), + } } - pub fn error(mut self) -> ::Error { self.tester.error() } + pub fn error(self) -> E { + let response = self.get_response(); + assert_eq!(response.status_code, StatusCode::Err); + >::try_from(response.payload).unwrap().into_inner() + } - pub fn assert_error(mut self) -> Self { - self.tester.assert_error(); + pub fn assert_error(self) -> Self { + // self.context.assert_error(); self } - pub fn assert_success(mut self) -> Self { - self.tester.assert_success(); + pub fn assert_success(self) -> Self { + // self.context.assert_success(); self } + + pub fn sdk(&self) -> FlowySDK { self.context.sdk.clone() } + + fn dispatch(&self) -> Arc { 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 { - context: TesterContext, - err_phantom: PhantomData, +#[derive(Clone)] +pub struct TestContext { + sdk: FlowyTestSDK, + request: Option, + response: Option, } -impl RandomUserTester -where - Error: FromBytes + Debug, -{ - pub fn new() -> Self { +impl TestContext { + pub fn new(sdk: FlowyTestSDK) -> Self { Self { - context: TesterContext::default(), - err_phantom: PhantomData, + sdk, + request: None, + response: None, } } } - -impl TesterTrait for RandomUserTester -where - Error: FromBytes + Debug, -{ - type Error = Error; - - fn mut_context(&mut self) -> &mut TesterContext { &mut self.context } - - fn context(&self) -> &TesterContext { &self.context } -} - pub struct SignUpContext { pub user_detail: UserDetail, pub password: String, diff --git a/rust-lib/flowy-test/src/helper.rs b/rust-lib/flowy-test/src/helper.rs index 6a6fbdb3bc..f9844ef0c3 100644 --- a/rust-lib/flowy-test/src/helper.rs +++ b/rust-lib/flowy-test/src/helper.rs @@ -1,13 +1,14 @@ 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_user::errors::{ErrorBuilder, ErrorCode, UserError}; use flowy_workspace::{ entities::workspace::{CreateWorkspaceRequest, QueryWorkspaceRequest, Workspace}, errors::WorkspaceError, event::WorkspaceEvent::{CreateWorkspace, OpenWorkspace}, }; -use std::{fs, path::PathBuf}; +use std::{fs, path::PathBuf, sync::Arc}; pub fn root_dir() -> String { // 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: &'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, user_id: &str) -> Result<(), UserError> { let key = format!("{}{}", user_id, DEFAULT_WORKSPACE); if KV::get_bool(&key).unwrap_or(false) { 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(); let request = ModuleRequest::new(CreateWorkspace).payload(payload); - let result = EventDispatch::sync_send(request) + let result = EventDispatch::sync_send(dispatch.clone(), request) .parse::() .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 { workspace_id: Some(workspace.id.clone()), } @@ -63,7 +63,7 @@ pub(crate) fn create_default_workspace_if_need(user_id: &str) -> Result<(), User .unwrap(); let request = ModuleRequest::new(OpenWorkspace).payload(query); - let _result = EventDispatch::sync_send(request) + let _result = EventDispatch::sync_send(dispatch.clone(), request) .parse::() .unwrap() .unwrap(); diff --git a/rust-lib/flowy-test/src/lib.rs b/rust-lib/flowy-test/src/lib.rs index 878c9d1c33..cae7a5b08c 100644 --- a/rust-lib/flowy-test/src/lib.rs +++ b/rust-lib/flowy-test/src/lib.rs @@ -1,21 +1,34 @@ pub mod builder; 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 std::sync::Once; pub mod prelude { - pub use crate::{builder::*, helper::*}; + pub use crate::{builder::*, helper::*, *}; pub use flowy_dispatch::prelude::*; } -static INIT: Once = Once::new(); -pub fn init_test_sdk() { - let root_dir = root_dir(); +pub type FlowyTestSDK = FlowySDK; - INIT.call_once(|| { - FlowySDK::construct_with(&root_dir); - }); +#[derive(Clone)] +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) } diff --git a/rust-lib/flowy-test/src/tester.rs b/rust-lib/flowy-test/src/tester.rs deleted file mode 100644 index aa8f3e5bf1..0000000000 --- a/rust-lib/flowy-test/src/tester.rs +++ /dev/null @@ -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, - response: Option, - 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(&mut self, event: E) - where - E: Eq + Hash + Debug + Clone + Display, - { - self.mut_context().request = Some(ModuleRequest::new(event)); - } - - fn set_payload

(&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 - fn parse(&mut self) -> R - where - R: FromBytes, - { - let response = self.mut_context().response.clone().unwrap(); - match response.parse::() { - 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); - >::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::().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::().unwrap().unwrap(); - - user_detail - } - - fn login_if_need(&self) -> UserDetail { - match EventDispatch::sync_send(ModuleRequest::new(GetUserProfile)) - .parse::() - .unwrap() - { - Ok(user_detail) => user_detail, - Err(_e) => self.sign_in(), - } - } - - fn logout(&self) { let _ = EventDispatch::sync_send(ModuleRequest::new(SignOut)); } -} diff --git a/rust-lib/flowy-test/src/workspace_builder.rs b/rust-lib/flowy-test/src/workspace_builder.rs new file mode 100644 index 0000000000..80b74518f5 --- /dev/null +++ b/rust-lib/flowy-test/src/workspace_builder.rs @@ -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; + +pub struct WorkspaceTestBuilder { + workspace: Option, + app: Option, + view: Option, + inner: Builder, +} + +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) { + let inner = self.inner; + for action in actions { + match action { + WorkspaceAction::CreateWorkspace(request) => { + let workspace = inner + .clone() + .event(CreateWorkspace) + .request(request) + .sync_send() + .parse::(); + self.workspace = Some(workspace); + }, + WorkspaceAction::ReadWorkspace(request) => { + let mut repeated_workspace = inner + .clone() + .event(ReadWorkspaces) + .request(request) + .sync_send() + .parse::(); + + debug_assert_eq!(repeated_workspace.len(), 1, "Default workspace not found"); + repeated_workspace.drain(..1).collect::>().pop() + }, + } + } + } +} diff --git a/rust-lib/flowy-user/Cargo.toml b/rust-lib/flowy-user/Cargo.toml index 906aac45de..c74210a070 100644 --- a/rust-lib/flowy-user/Cargo.toml +++ b/rust-lib/flowy-user/Cargo.toml @@ -49,4 +49,4 @@ futures = "0.3.15" serial_test = "0.5.1" [features] -mock_server = [] \ No newline at end of file +http_server = [] \ No newline at end of file diff --git a/rust-lib/flowy-user/src/entities/user_detail.rs b/rust-lib/flowy-user/src/entities/user_detail.rs index a867afdeca..b0e76f4950 100644 --- a/rust-lib/flowy-user/src/entities/user_detail.rs +++ b/rust-lib/flowy-user/src/entities/user_detail.rs @@ -17,7 +17,7 @@ impl std::default::Default for UserStatus { fn default() -> Self { UserStatus::Unknown } } -#[derive(ProtoBuf, Default, Debug, PartialEq, Eq)] +#[derive(ProtoBuf, Default, Debug, PartialEq, Eq, Clone)] pub struct UserDetail { #[pb(index = 1)] pub id: String, @@ -135,36 +135,19 @@ impl TryInto for UpdateUserRequest { let name = match self.name { None => None, - Some(name) => Some( - UserName::parse(name) - .map_err(|e| ErrorBuilder::new(e).build())? - .0, - ), + Some(name) => Some(UserName::parse(name).map_err(|e| ErrorBuilder::new(e).build())?.0), }; let email = match self.email { None => None, - Some(email) => Some( - UserEmail::parse(email) - .map_err(|e| ErrorBuilder::new(e).build())? - .0, - ), + Some(email) => Some(UserEmail::parse(email).map_err(|e| ErrorBuilder::new(e).build())?.0), }; let password = match self.password { None => None, - Some(password) => Some( - UserPassword::parse(password) - .map_err(|e| ErrorBuilder::new(e).build())? - .0, - ), + Some(password) => Some(UserPassword::parse(password).map_err(|e| ErrorBuilder::new(e).build())?.0), }; - Ok(UpdateUserParams { - id, - name, - email, - password, - }) + Ok(UpdateUserParams { id, name, email, password }) } } diff --git a/rust-lib/flowy-user/src/services/server/mod.rs b/rust-lib/flowy-user/src/services/server/mod.rs index 2b84a25e22..f3e8ff72b5 100644 --- a/rust-lib/flowy-user/src/services/server/mod.rs +++ b/rust-lib/flowy-user/src/services/server/mod.rs @@ -20,9 +20,9 @@ pub trait UserServerAPI { } pub(crate) fn construct_user_server() -> Arc { - if cfg!(feature = "mock_server") { - Arc::new(UserServerMock {}) - } else { + if cfg!(feature = "http_server") { Arc::new(UserServer {}) + } else { + Arc::new(UserServerMock {}) } } diff --git a/rust-lib/flowy-user/src/services/user/database.rs b/rust-lib/flowy-user/src/services/user/database.rs index 7b32fb8c92..bc91ffd530 100644 --- a/rust-lib/flowy-user/src/services/user/database.rs +++ b/rust-lib/flowy-user/src/services/user/database.rs @@ -3,7 +3,7 @@ use flowy_database::{DBConnection, Database}; use flowy_sqlite::ConnectionPool; use lazy_static::lazy_static; 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}; lazy_static! { static ref DB: RwLock> = RwLock::new(None); diff --git a/rust-lib/flowy-user/src/services/user/user_session.rs b/rust-lib/flowy-user/src/services/user/user_session.rs index effbb11837..89011700fd 100644 --- a/rust-lib/flowy-user/src/services/user/user_session.rs +++ b/rust-lib/flowy-user/src/services/user/user_session.rs @@ -170,7 +170,7 @@ impl UserSession { } fn set_session(&self, session: Option) -> Result<(), UserError> { - log::trace!("Update user session: {:?}", session); + log::debug!("Update user session: {:?}", session); match &session { 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()), diff --git a/rust-lib/flowy-user/tests/event/auth_test.rs b/rust-lib/flowy-user/tests/event/auth_test.rs index 93b74e3d9d..cce8ce6190 100644 --- a/rust-lib/flowy-user/tests/event/auth_test.rs +++ b/rust-lib/flowy-user/tests/event/auth_test.rs @@ -1,19 +1,13 @@ 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 serial_test::*; -#[test] -#[serial] -fn sign_up_success() { - let user_detail = UserTestBuilder::new().sign_up().user_detail; - log::info!("{:?}", user_detail); -} - #[test] #[serial] fn sign_up_with_invalid_email() { for email in invalid_email_test_case() { + let sdk = init_test_sdk(); let request = SignUpRequest { email: email.to_string(), name: valid_name(), @@ -21,7 +15,7 @@ fn sign_up_with_invalid_email() { }; 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 ); } @@ -30,28 +24,30 @@ fn sign_up_with_invalid_email() { #[serial] fn sign_up_with_invalid_password() { for password in invalid_password_test_case() { + let sdk = init_test_sdk(); let request = SignUpRequest { email: random_email(), name: valid_name(), password, }; - UserTestBuilder::new().event(SignUp).request(request).sync_send().assert_error(); + UserTestBuilder::new(sdk).event(SignUp).request(request).sync_send().assert_error(); } } #[test] #[serial] fn sign_in_success() { - let context = UserTestBuilder::new().sign_up(); - let _ = UserTestBuilder::new().event(SignOut).sync_send(); + let sdk = init_test_sdk(); + let context = UserTestBuilder::new(sdk.clone()).sign_up(); + let _ = UserTestBuilder::new(sdk.clone()).event(SignOut).sync_send(); let request = SignInRequest { email: context.user_detail.email, password: context.password, }; - let response = UserTestBuilder::new() + let response = UserTestBuilder::new(sdk) .event(SignIn) .request(request) .sync_send() @@ -63,13 +59,14 @@ fn sign_in_success() { #[serial] fn sign_in_with_invalid_email() { for email in invalid_email_test_case() { + let sdk = init_test_sdk(); let request = SignInRequest { email: email.to_string(), password: login_password(), }; 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 ); } @@ -79,11 +76,12 @@ fn sign_in_with_invalid_email() { #[serial] fn sign_in_with_invalid_password() { for password in invalid_password_test_case() { + let sdk = init_test_sdk(); let request = SignInRequest { email: random_email(), password, }; - UserTestBuilder::new().event(SignIn).request(request).sync_send().assert_error(); + UserTestBuilder::new(sdk).event(SignIn).request(request).sync_send().assert_error(); } } diff --git a/rust-lib/flowy-user/tests/event/user_profile_test.rs b/rust-lib/flowy-user/tests/event/user_profile_test.rs index c72d9bca5a..eb4fddb64f 100644 --- a/rust-lib/flowy-user/tests/event/user_profile_test.rs +++ b/rust-lib/flowy-user/tests/event/user_profile_test.rs @@ -1,22 +1,24 @@ use crate::helper::*; 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 serial_test::*; #[test] #[serial] -fn user_status_get_failed() { - let tester = UserTestBuilder::new().event(GetUserProfile).assert_error().sync_send(); - assert!(tester.get_user_detail().is_none()) +fn user_profile_get_failed() { + let sdk = init_test_sdk(); + let result = UserTestBuilder::new(sdk).event(GetUserProfile).assert_error().sync_send(); + assert!(result.user_detail().is_none()) } #[test] #[serial] -fn user_detail_get() { - let user_detail = UserTestBuilder::new().sign_up().user_detail; +fn user_profile_get() { + 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::(); + let user_detail2 = UserTestBuilder::new(sdk).event(GetUserProfile).sync_send().parse::(); assert_eq!(user_detail, user_detail2); } @@ -24,12 +26,13 @@ fn user_detail_get() { #[test] #[serial] 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 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) .assert_error() .sync_send() @@ -41,13 +44,14 @@ fn user_update_with_name() { #[test] #[serial] 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 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) .assert_error() .sync_send() @@ -59,11 +63,12 @@ fn user_update_with_email() { #[test] #[serial] 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 request = UpdateUserRequest::new(&user_detail.id).password(&new_password); - let _ = UserTestBuilder::new() + let _ = UserTestBuilder::new(sdk) .event(UpdateUser) .request(request) .sync_send() @@ -73,11 +78,17 @@ fn user_update_with_password() { #[test] #[serial] 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() { let request = UpdateUserRequest::new(&user_detail.id).email(&email); 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 ); } @@ -86,19 +97,29 @@ fn user_update_with_invalid_email() { #[test] #[serial] 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() { 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] #[serial] 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(""); - UserTestBuilder::new().event(UpdateUser).request(request).sync_send().assert_error(); + UserTestBuilder::new(sdk) + .event(UpdateUser) + .request(request) + .sync_send() + .assert_error(); } diff --git a/rust-lib/flowy-workspace/Cargo.toml b/rust-lib/flowy-workspace/Cargo.toml index 884499f85c..3f89cf7186 100644 --- a/rust-lib/flowy-workspace/Cargo.toml +++ b/rust-lib/flowy-workspace/Cargo.toml @@ -37,4 +37,4 @@ serial_test = "0.5.1" [features] -mock_server = [] \ No newline at end of file +http_server = [] \ No newline at end of file diff --git a/rust-lib/flowy-workspace/src/handlers/workspace_handler.rs b/rust-lib/flowy-workspace/src/handlers/workspace_handler.rs index f7d877cc64..c0e2afc27f 100644 --- a/rust-lib/flowy-workspace/src/handlers/workspace_handler.rs +++ b/rust-lib/flowy-workspace/src/handlers/workspace_handler.rs @@ -1,8 +1,4 @@ -use crate::{ - entities::workspace::*, - errors::{ErrorBuilder, ErrorCode, WorkspaceError}, - services::WorkspaceController, -}; +use crate::{entities::workspace::*, errors::WorkspaceError, services::WorkspaceController}; use flowy_dispatch::prelude::{data_result, Data, DataResult, Unit}; use std::{convert::TryInto, sync::Arc}; diff --git a/rust-lib/flowy-workspace/src/services/server/mod.rs b/rust-lib/flowy-workspace/src/services/server/mod.rs index adb12987a6..85c64fcb54 100644 --- a/rust-lib/flowy-workspace/src/services/server/mod.rs +++ b/rust-lib/flowy-workspace/src/services/server/mod.rs @@ -51,9 +51,9 @@ pub trait WorkspaceServerAPI { } pub(crate) fn construct_workspace_server() -> Arc { - if cfg!(feature = "mock_server") { - Arc::new(WorkspaceServerMock {}) - } else { + if cfg!(feature = "http_server") { Arc::new(WorkspaceServer {}) + } else { + Arc::new(WorkspaceServerMock {}) } } diff --git a/rust-lib/flowy-workspace/src/services/workspace_controller.rs b/rust-lib/flowy-workspace/src/services/workspace_controller.rs index ead360848d..66842234a9 100644 --- a/rust-lib/flowy-workspace/src/services/workspace_controller.rs +++ b/rust-lib/flowy-workspace/src/services/workspace_controller.rs @@ -6,7 +6,7 @@ use crate::{ services::{helper::spawn, server::Server, AppController}, sql_tables::workspace::{WorkspaceSql, WorkspaceTable, WorkspaceTableChangeset}, }; -use flowy_dispatch::prelude::DispatchFuture; + use flowy_infra::kv::KV; use std::sync::Arc; diff --git a/rust-lib/flowy-workspace/tests/workspace/app_test.rs b/rust-lib/flowy-workspace/tests/workspace/app_test.rs index 6cf711eae7..671b85077f 100644 --- a/rust-lib/flowy-workspace/tests/workspace/app_test.rs +++ b/rust-lib/flowy-workspace/tests/workspace/app_test.rs @@ -1,6 +1,6 @@ use crate::helper::*; +use flowy_test::prelude::*; -use flowy_test::builder::UserTestBuilder; use flowy_workspace::entities::{ app::{QueryAppRequest, UpdateAppRequest}, view::*, @@ -8,40 +8,39 @@ use flowy_workspace::entities::{ #[test] fn app_create() { - let _ = UserTestBuilder::new().sign_up(); - let workspace = create_workspace("Workspace", ""); - let app = create_app("App A", "AppFlowy Github Project", &workspace.id); + let sdk = TestSDKBuilder::new().sign_up().build(); + let workspace = create_workspace(&sdk, "Workspace", ""); + let app = create_app(&sdk, "App A", "AppFlowy Github Project", &workspace.id); dbg!(&app); } #[test] #[should_panic] fn app_delete() { - let _ = UserTestBuilder::new().sign_up(); - - let workspace = create_workspace("Workspace", ""); - let app = create_app("App A", "AppFlowy Github Project", &workspace.id); - delete_app(&app.id); + let sdk = TestSDKBuilder::new().sign_up().build(); + let workspace = create_workspace(&sdk, "Workspace", ""); + let app = create_app(&sdk, "App A", "AppFlowy Github Project", &workspace.id); + delete_app(&sdk, &app.id); let query = QueryAppRequest::new(&app.id); - let _ = read_app(query); + let _ = read_app(&sdk, query); } #[test] fn app_read() { - let _ = UserTestBuilder::new().sign_up(); + let sdk = TestSDKBuilder::new().sign_up().build(); - let workspace = create_workspace("Workspace", ""); - 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 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); } #[test] fn app_create_with_view() { - let _a = UserTestBuilder::new().sign_up(); - let workspace = create_workspace("Workspace", ""); - let app = create_app("App A", "AppFlowy Github Project", &workspace.id); + let sdk = TestSDKBuilder::new().sign_up().build(); + let workspace = create_workspace(&sdk, "Workspace", ""); + let app = create_app(&sdk, "App A", "AppFlowy Github Project", &workspace.id); let request_a = CreateViewRequest { belong_to_id: app.id.clone(), name: "View A".to_string(), @@ -58,11 +57,11 @@ fn app_create_with_view() { view_type: ViewType::Doc, }; - let view_a = create_view_with_request(request_a); - let view_b = create_view_with_request(request_b); + let view_a = create_view_with_request(&sdk, request_a); + let view_b = create_view_with_request(&sdk, request_b); 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[1], view_b); @@ -70,24 +69,24 @@ fn app_create_with_view() { #[test] fn app_set_trash_flag() { - let _ = UserTestBuilder::new().sign_up(); - let app_id = create_app_with_trash_flag(); + let sdk = TestSDKBuilder::new().sign_up().build(); + let app_id = create_app_with_trash_flag(&sdk); let query = QueryAppRequest::new(&app_id).set_is_trash(true); - let _ = read_app(query); + let _ = read_app(&sdk, query); } #[test] #[should_panic] fn app_set_trash_flag_2() { - let _ = UserTestBuilder::new().sign_up(); - let app_id = create_app_with_trash_flag(); + let sdk = TestSDKBuilder::new().sign_up().build(); + let app_id = create_app_with_trash_flag(&sdk); let query = QueryAppRequest::new(&app_id); - let _ = read_app(query); + let _ = read_app(&sdk, query); } -fn create_app_with_trash_flag() -> String { - let workspace = create_workspace("Workspace", ""); - let app = create_app("App A", "AppFlowy Github Project", &workspace.id); +fn create_app_with_trash_flag(sdk: &FlowyTestSDK) -> String { + let workspace = create_workspace(sdk, "Workspace", ""); + let app = create_app(sdk, "App A", "AppFlowy Github Project", &workspace.id); let request = UpdateAppRequest { app_id: app.id.clone(), name: None, @@ -95,7 +94,7 @@ fn create_app_with_trash_flag() -> String { color_style: None, is_trash: Some(true), }; - update_app(request); + update_app(sdk, request); app.id } diff --git a/rust-lib/flowy-workspace/tests/workspace/helper.rs b/rust-lib/flowy-workspace/tests/workspace/helper.rs index 6f78719e0d..5117d5eb2b 100644 --- a/rust-lib/flowy-workspace/tests/workspace/helper.rs +++ b/rust-lib/flowy-workspace/tests/workspace/helper.rs @@ -1,4 +1,4 @@ -use flowy_test::builder::{UserTestBuilder, WorkspaceTestBuilder}; +use flowy_test::prelude::*; use flowy_workspace::{ entities::{app::*, view::*, workspace::*}, event::WorkspaceEvent::*, @@ -11,13 +11,13 @@ pub(crate) fn invalid_workspace_name_test_case() -> Vec { .collect::>() } -pub fn create_workspace(name: &str, desc: &str) -> Workspace { +pub fn create_workspace(sdk: &FlowyTestSDK, name: &str, desc: &str) -> Workspace { let request = CreateWorkspaceRequest { name: name.to_owned(), desc: desc.to_owned(), }; - let workspace = WorkspaceTestBuilder::new() + let workspace = WorkspaceTestBuilder::new(sdk.clone()) .event(CreateWorkspace) .request(request) .sync_send() @@ -25,8 +25,8 @@ pub fn create_workspace(name: &str, desc: &str) -> Workspace { workspace } -pub fn read_workspaces(request: QueryWorkspaceRequest) -> Option { - let mut repeated_workspace = WorkspaceTestBuilder::new() +pub fn read_workspaces(sdk: &FlowyTestSDK, request: QueryWorkspaceRequest) -> Option { + let mut repeated_workspace = WorkspaceTestBuilder::new(sdk.clone()) .event(ReadWorkspaces) .request(request) .sync_send() @@ -36,7 +36,7 @@ pub fn read_workspaces(request: QueryWorkspaceRequest) -> Option { repeated_workspace.drain(..1).collect::>().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 { workspace_id: workspace_id.to_owned(), name: name.to_string(), @@ -44,7 +44,7 @@ pub fn create_app(name: &str, desc: &str, workspace_id: &str) -> App { color_style: Default::default(), }; - let app = WorkspaceTestBuilder::new() + let app = WorkspaceTestBuilder::new(sdk.clone()) .event(CreateApp) .request(create_app_request) .sync_send() @@ -52,18 +52,23 @@ pub fn create_app(name: &str, desc: &str, workspace_id: &str) -> App { app } -pub fn delete_app(app_id: &str) { +pub fn delete_app(sdk: &FlowyTestSDK, app_id: &str) { let delete_app_request = DeleteAppRequest { 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 { - let app = WorkspaceTestBuilder::new() +pub fn read_app(sdk: &FlowyTestSDK, request: QueryAppRequest) -> App { + let app = WorkspaceTestBuilder::new(sdk.clone()) .event(ReadApp) .request(request) .sync_send() @@ -72,8 +77,8 @@ pub fn read_app(request: QueryAppRequest) -> App { app } -pub fn create_view_with_request(request: CreateViewRequest) -> View { - let view = WorkspaceTestBuilder::new() +pub fn create_view_with_request(sdk: &FlowyTestSDK, request: CreateViewRequest) -> View { + let view = WorkspaceTestBuilder::new(sdk.clone()) .event(CreateView) .request(request) .sync_send() @@ -82,8 +87,8 @@ pub fn create_view_with_request(request: CreateViewRequest) -> View { view } -pub fn create_view(workspace_id: &str) -> View { - let app = create_app("App A", "AppFlowy Github Project", workspace_id); +pub fn create_view(sdk: &FlowyTestSDK, workspace_id: &str) -> View { + let app = create_app(sdk, "App A", "AppFlowy Github Project", workspace_id); let request = CreateViewRequest { belong_to_id: app.id.clone(), name: "View A".to_string(), @@ -92,13 +97,18 @@ pub fn create_view(workspace_id: &str) -> View { 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 { - WorkspaceTestBuilder::new() +pub fn read_view(sdk: &FlowyTestSDK, request: QueryViewRequest) -> View { + WorkspaceTestBuilder::new(sdk.clone()) .event(ReadView) .request(request) .sync_send() diff --git a/rust-lib/flowy-workspace/tests/workspace/view_test.rs b/rust-lib/flowy-workspace/tests/workspace/view_test.rs index 1a688629d2..17f7d0cc8e 100644 --- a/rust-lib/flowy-workspace/tests/workspace/view_test.rs +++ b/rust-lib/flowy-workspace/tests/workspace/view_test.rs @@ -1,37 +1,36 @@ use crate::helper::*; -use flowy_test::builder::UserTestBuilder; +use flowy_test::{FlowyTestSDK, TestSDKBuilder}; use flowy_workspace::entities::view::*; #[test] fn view_create() { - let _ = UserTestBuilder::new().sign_up(); - - let workspace = create_workspace("Workspace", ""); - let _ = create_view(&workspace.id); + let sdk = TestSDKBuilder::new().sign_up().build(); + let workspace = create_workspace(&sdk, "Workspace", ""); + let _ = create_view(&sdk, &workspace.id); } #[test] fn view_set_trash_flag() { - let _ = UserTestBuilder::new().sign_up(); - let view_id = create_view_with_trash_flag(); + let sdk = TestSDKBuilder::new().sign_up().build(); + let view_id = create_view_with_trash_flag(&sdk); let query = QueryViewRequest::new(&view_id).set_is_trash(true); - let _ = read_view(query); + let _ = read_view(&sdk, query); } #[test] #[should_panic] 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 _ = read_view(query); + let _ = read_view(&sdk, query); } -fn create_view_with_trash_flag() -> String { - let workspace = create_workspace("Workspace", ""); - let view = create_view(&workspace.id); +fn create_view_with_trash_flag(sdk: &FlowyTestSDK) -> String { + let workspace = create_workspace(sdk, "Workspace", ""); + let view = create_view(sdk, &workspace.id); let request = UpdateViewRequest { view_id: view.id.clone(), name: None, @@ -39,7 +38,7 @@ fn create_view_with_trash_flag() -> String { thumbnail: None, is_trash: Some(true), }; - update_view(request); + update_view(sdk, request); view.id } diff --git a/rust-lib/flowy-workspace/tests/workspace/workspace_test.rs b/rust-lib/flowy-workspace/tests/workspace/workspace_test.rs index 67849413b7..a102372d3b 100644 --- a/rust-lib/flowy-workspace/tests/workspace/workspace_test.rs +++ b/rust-lib/flowy-workspace/tests/workspace/workspace_test.rs @@ -1,5 +1,5 @@ use crate::helper::*; -use flowy_test::builder::*; +use flowy_test::{builder::*, TestSDKBuilder}; use flowy_workspace::{ entities::workspace::{CreateWorkspaceRequest, QueryWorkspaceRequest, RepeatedWorkspace}, event::WorkspaceEvent::*, @@ -7,14 +7,17 @@ use flowy_workspace::{ }; #[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] fn workspace_read_all() { - let _ = UserTestBuilder::new().sign_up(); - let _ = create_workspace("Workspace A", "workspace_create_and_then_get_workspace_success"); + let sdk = TestSDKBuilder::new().sign_up().build(); + 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) .request(QueryWorkspaceRequest::new()) .sync_send() @@ -25,29 +28,32 @@ fn workspace_read_all() { #[test] 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 workspace_from_db = read_workspaces(request).unwrap(); + let workspace_from_db = read_workspaces(&sdk, request).unwrap(); assert_eq!(workspace.name, workspace_from_db.name); } #[test] fn workspace_create_with_apps() { - let workspace = create_workspace("Workspace", ""); - let app = create_app("App A", "AppFlowy Github Project", &workspace.id); + let sdk = TestSDKBuilder::new().sign_up().build(); + 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 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()); } #[test] fn workspace_create_with_invalid_name() { + let sdk = TestSDKBuilder::new().sign_up().build(); 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() }; assert_eq!( - WorkspaceTestBuilder::new() + WorkspaceTestBuilder::new(sdk.clone()) .event(CreateWorkspace) .request(request) .sync_send() @@ -60,11 +66,11 @@ fn workspace_create_with_invalid_name() { #[test] 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() { let request = CreateWorkspaceRequest { name, desc: "".to_owned() }; assert_eq!( - WorkspaceTestBuilder::new() + WorkspaceTestBuilder::new(sdk.clone()) .event(CreateWorkspace) .request(request) .sync_send() diff --git a/scripts/makefile/tests.toml b/scripts/makefile/tests.toml index 545670e505..bf177ce5f8 100644 --- a/scripts/makefile/tests.toml +++ b/scripts/makefile/tests.toml @@ -5,16 +5,15 @@ dependencies = ["rm_cache"] description = "Build desktop targets." script = ''' cd rust-lib -cargo test --features "flowy-workspace/mock_server","flowy-user/mock_server" +cargo test ''' [tasks.test_remote] -dependencies = ["rm_cache", "run_server"] -[tasks.run_test_remote_command] +dependencies = ["rm_cache"] script = """ cd rust-lib -cargo test +cargo test --features "flowy-workspace/http_server","flowy-user/http_server" """