[rust]: fix bugs to pass backend tests

This commit is contained in:
appflowy 2021-11-09 15:32:57 +08:00
parent 823c9f9bd6
commit 2972c40b9b
20 changed files with 84 additions and 116 deletions

View File

@ -1,7 +1,10 @@
use crate::{
entities::{token::Token, user::UserTable},
service::user::{hash_password, verify_password, LoggedUser},
sqlx_ext::{map_sqlx_error, DBTransaction, SqlBuilder},
};
use anyhow::Context;
use sqlx::{PgPool, Postgres};
use chrono::Utc;
use flowy_net::{
errors::{invalid_params, ErrorCode, ServerError},
response::FlowyResponse,
@ -10,12 +13,7 @@ use flowy_user_infra::{
parser::{UserEmail, UserName, UserPassword},
protobuf::{SignInParams, SignInResponse, SignUpParams, SignUpResponse, UpdateUserParams, UserProfile},
};
use crate::{
entities::{token::Token, user::UserTable},
service::user::{hash_password, verify_password, LoggedUser},
sqlx_ext::{map_sqlx_error, DBTransaction, SqlBuilder},
};
use sqlx::{PgPool, Postgres};
use super::AUTHORIZED_USERS;
use crate::service::user::user_default::create_default_workspace;

View File

@ -210,7 +210,7 @@ async fn workspace_list_read() {
let _ = server.create_workspace(params).await;
}
let read_params = WorkspaceIdentifier::new();
let read_params = WorkspaceIdentifier::new(None);
let workspaces = server.read_workspaces(read_params).await;
assert_eq!(workspaces.len(), 4);
}

View File

@ -4,11 +4,7 @@ use diesel::{Connection, SqliteConnection};
use flowy_derive::ProtoBuf;
use flowy_sqlite::{DBConnection, Database, PoolConfig};
use lazy_static::lazy_static;
use std::{
collections::HashMap,
path::Path,
sync::{PoisonError, RwLock, RwLockWriteGuard},
};
use std::{collections::HashMap, path::Path, sync::RwLock};
const DB_NAME: &str = "kv.db";
lazy_static! {

View File

@ -102,37 +102,6 @@ mod tests {
say("hello world");
}
#[test]
fn test_log2() {
let env_filter = EnvFilter::new("Debug");
let file_appender = tracing_appender::rolling::daily(".", "flowy_log_test");
let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender);
let subscriber = tracing_subscriber::fmt()
.with_target(false)
.with_max_level(tracing::Level::TRACE)
.with_writer(std::io::stderr)
.with_thread_ids(true)
.with_writer(non_blocking)
.json()
.compact()
.finish()
.with(env_filter);
let formatting_layer = FlowyFormattingLayer::new(std::io::stdout);
let _ = set_global_default(subscriber.with(JsonStorageLayer).with(formatting_layer))
.map_err(|e| format!("{:?}", e))
.unwrap();
let _ = LogTracer::builder()
.with_max_level(LevelFilter::Trace)
.init()
.map_err(|e| format!("{:?}", e))
.unwrap();
tracing::info!("😁");
}
#[tracing::instrument(name = "say")]
fn say(s: &str) {
tracing::info!("{}", s);

View File

@ -110,8 +110,8 @@ async fn _listen_user_status(
Ok(status) => {
let result = || async {
match status {
UserStatus::Login { .. } => {
let _ = workspace_controller.user_did_login()?;
UserStatus::Login { token } => {
let _ = workspace_controller.user_did_sign_in(&token)?;
},
UserStatus::Logout { .. } => {
workspace_controller.user_did_logout();
@ -119,8 +119,8 @@ async fn _listen_user_status(
UserStatus::Expired { .. } => {
workspace_controller.user_session_expired();
},
UserStatus::SignUp { .. } => {
let _ = workspace_controller.user_did_sign_up().await?;
UserStatus::SignUp { profile } => {
let _ = workspace_controller.user_did_sign_up(&profile.token).await?;
},
}
Ok::<(), WorkspaceError>(())

View File

@ -40,8 +40,6 @@ impl FlowyTest {
pub fn setup_with(server_config: ServerConfig) -> Self {
let config = FlowySDKConfig::new(&root_dir(), server_config).log_filter("debug");
let sdk = FlowySDK::new(config);
let _ = sdk.workspace.init().unwrap();
Self { sdk }
}

View File

@ -7,6 +7,7 @@ use flowy_workspace::{
view::*,
workspace::*,
},
errors::ErrorCode,
event::WorkspaceEvent::*,
};
@ -98,11 +99,11 @@ impl ViewTest {
}
}
pub fn invalid_workspace_name_test_case() -> Vec<String> {
vec!["", "1234".repeat(100).as_str()]
.iter()
.map(|s| s.to_string())
.collect::<Vec<_>>()
pub fn invalid_workspace_name_test_case() -> Vec<(String, ErrorCode)> {
vec![
("".to_owned(), ErrorCode::WorkspaceNameInvalid),
("1234".repeat(100), ErrorCode::WorkspaceNameTooLong),
]
}
pub async fn create_workspace(sdk: &FlowyTestSDK, name: &str, desc: &str) -> Workspace {
@ -131,7 +132,7 @@ async fn open_workspace(sdk: &FlowyTestSDK, workspace_id: &str) {
.await;
}
pub async fn read_workspace(sdk: &FlowyTestSDK, request: QueryWorkspaceRequest) -> Option<Workspace> {
pub async fn read_workspace(sdk: &FlowyTestSDK, request: QueryWorkspaceRequest) -> Vec<Workspace> {
let mut repeated_workspace = FlowyWorkspaceTest::new(sdk.clone())
.event(ReadWorkspaces)
.request(request.clone())
@ -139,7 +140,7 @@ pub async fn read_workspace(sdk: &FlowyTestSDK, request: QueryWorkspaceRequest)
.await
.parse::<RepeatedWorkspace>();
let mut workspaces;
let workspaces;
if let Some(workspace_id) = &request.workspace_id {
workspaces = repeated_workspace
.into_inner()
@ -151,7 +152,7 @@ pub async fn read_workspace(sdk: &FlowyTestSDK, request: QueryWorkspaceRequest)
workspaces = repeated_workspace.items;
}
workspaces.drain(..1).collect::<Vec<Workspace>>().pop()
workspaces
}
pub async fn create_app(sdk: &FlowyTestSDK, name: &str, desc: &str, workspace_id: &str) -> App {

View File

@ -75,7 +75,6 @@ impl UserSession {
}
pub fn init(&self) {
log::debug!("😁😁😁 user did login");
match self.get_session() {
Ok(session) => {
let _ = self.status_notifier.send(UserStatus::Login { token: session.token });

View File

@ -50,7 +50,7 @@ async fn user_update_with_name() {
async fn user_update_with_email() {
let test = FlowyTest::setup();
let user = test.init_user().await;
let new_email = format!("{}@gmai.com", uuid());
let new_email = format!("{}@gmail.com", uuid());
let request = UpdateUserRequest::new(&user.id).email(&new_email);
let _ = UserTest::new(test.sdk()).event(UpdateUser).request(request).sync_send();
let user_profile = UserTest::new(test.sdk())

View File

@ -10,12 +10,7 @@ pub struct QueryWorkspaceRequest {
}
impl QueryWorkspaceRequest {
pub fn new() -> Self { Self { workspace_id: None } }
pub fn workspace_id(mut self, workspace_id: &str) -> Self {
self.workspace_id = Some(workspace_id.to_owned());
self
}
pub fn new(workspace_id: Option<String>) -> Self { Self { workspace_id } }
}
// Read all workspaces if the workspace_id is None

View File

@ -15,6 +15,7 @@ pub mod handlers;
mod notify;
pub mod protobuf;
mod sql_tables;
mod util;
pub mod prelude {
pub use flowy_workspace_infra::entities::{app::*, trash::*, view::*, workspace::*};

View File

@ -12,7 +12,7 @@ use crate::{
errors::*,
module::{WorkspaceDatabase, WorkspaceUser},
notify::*,
services::{helper::spawn, server::Server, TrashCan, TrashEvent},
services::{server::Server, TrashCan, TrashEvent},
sql_tables::app::{AppTable, AppTableChangeset, AppTableSql},
};
@ -122,7 +122,7 @@ impl AppController {
fn update_app_on_server(&self, params: UpdateAppParams) -> Result<(), WorkspaceError> {
let token = self.user.token()?;
let server = self.server.clone();
spawn(async move {
tokio::spawn(async move {
match server.update_app(&token, params).await {
Ok(_) => {},
Err(e) => {
@ -139,7 +139,7 @@ impl AppController {
let token = self.user.token()?;
let server = self.server.clone();
let pool = self.database.db_pool()?;
spawn(async move {
tokio::spawn(async move {
// Opti: retry?
match server.read_app(&token, params).await {
Ok(Some(app)) => match pool.get() {

View File

@ -1,9 +0,0 @@
use tokio::task::JoinHandle;
pub fn spawn<F>(f: F) -> JoinHandle<F::Output>
where
F: std::future::Future + Send + 'static,
F::Output: Send + 'static,
{
tokio::spawn(f)
}

View File

@ -5,9 +5,7 @@ pub use workspace_controller::*;
mod app_controller;
mod database;
mod helper;
pub mod server;
pub(crate) mod server;
mod trash_can;
mod util;
mod view_controller;
mod workspace_controller;

View File

@ -10,7 +10,7 @@ use crate::{
errors::{WorkspaceError, WorkspaceResult},
module::{WorkspaceDatabase, WorkspaceUser},
notify::{send_anonymous_dart_notification, WorkspaceNotification},
services::{helper::spawn, server::Server},
services::server::Server,
sql_tables::trash::TrashTableSql,
};
@ -232,7 +232,7 @@ impl TrashCan {
let server = self.server.clone();
let pool = self.database.db_pool()?;
spawn(async move {
tokio::spawn(async move {
match server.read_trash(&token).await {
Ok(repeated_trash) => {
tracing::debug!("Remote trash count: {}", repeated_trash.items.len());

View File

@ -16,7 +16,7 @@ use crate::{
errors::{internal_error, WorkspaceError, WorkspaceResult},
module::{WorkspaceDatabase, WorkspaceUser},
notify::{send_dart_notification, WorkspaceNotification},
services::{helper::spawn, server::Server, TrashCan, TrashEvent},
services::{server::Server, TrashCan, TrashEvent},
sql_tables::view::{ViewTable, ViewTableChangeset, ViewTableSql},
};
@ -187,7 +187,7 @@ impl ViewController {
fn update_view_on_server(&self, params: UpdateViewParams) -> Result<(), WorkspaceError> {
let token = self.user.token()?;
let server = self.server.clone();
spawn(async move {
tokio::spawn(async move {
match server.update_view(&token, params).await {
Ok(_) => {},
Err(e) => {
@ -205,7 +205,7 @@ impl ViewController {
let server = self.server.clone();
let pool = self.database.db_pool()?;
// Opti: retry?
spawn(async move {
tokio::spawn(async move {
match server.read_view(&token, params).await {
Ok(Some(view)) => match pool.get() {
Ok(conn) => {

View File

@ -2,7 +2,7 @@ use crate::{
errors::*,
module::{WorkspaceDatabase, WorkspaceUser},
notify::*,
services::{helper::spawn, read_local_workspace_apps, server::Server, AppController, TrashCan, ViewController},
services::{read_local_workspace_apps, server::Server, AppController, TrashCan, ViewController},
sql_tables::workspace::{WorkspaceTable, WorkspaceTableChangeset, WorkspaceTableSql},
};
use chrono::Utc;
@ -12,12 +12,19 @@ use flowy_workspace_infra::{
entities::{app::RepeatedApp, workspace::*},
user_default,
};
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
use lazy_static::lazy_static;
use parking_lot::RwLock;
use std::{
collections::HashMap,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
};
static INIT_WORKSPACE: AtomicBool = AtomicBool::new(false);
lazy_static! {
static ref INIT_WORKSPACE: RwLock<HashMap<String, bool>> = RwLock::new(HashMap::new());
}
pub struct WorkspaceController {
pub user: Arc<dyn WorkspaceUser>,
@ -50,13 +57,14 @@ impl WorkspaceController {
}
}
fn init(&self) -> Result<(), WorkspaceError> {
if INIT_WORKSPACE.load(Ordering::SeqCst) {
return Ok(());
fn init(&self, token: &str) -> Result<(), WorkspaceError> {
if let Some(is_init) = INIT_WORKSPACE.read().get(token) {
if *is_init {
return Ok(());
}
}
INIT_WORKSPACE.write().insert(token.to_owned(), true);
log::debug!("workspace initialize");
INIT_WORKSPACE.store(true, Ordering::SeqCst);
let _ = self.server.init();
let _ = self.trash_can.init()?;
let _ = self.view_controller.init()?;
@ -65,9 +73,11 @@ impl WorkspaceController {
Ok(())
}
pub fn user_did_login(&self) -> WorkspaceResult<()> {
pub fn user_did_sign_in(&self, token: &str) -> WorkspaceResult<()> {
// TODO: (nathan) do something here
let _ = self.init()?;
log::debug!("workspace initialize after sign in");
let _ = self.init(token)?;
Ok(())
}
@ -79,7 +89,7 @@ impl WorkspaceController {
// TODO: (nathan) do something here
}
pub async fn user_did_sign_up(&self) -> WorkspaceResult<()> {
pub async fn user_did_sign_up(&self, _token: &str) -> WorkspaceResult<()> {
log::debug!("Create user default workspace");
let time = Utc::now();
let mut workspace = user_default::create_default_workspace(time);
@ -103,7 +113,9 @@ impl WorkspaceController {
send_dart_notification(&token, WorkspaceNotification::UserCreateWorkspace)
.payload(repeated_workspace)
.send();
let _ = self.init()?;
log::debug!("workspace initialize after sign up");
let _ = self.init(&token)?;
Ok(())
}
@ -290,7 +302,7 @@ impl WorkspaceController {
#[tracing::instrument(level = "debug", skip(self), err)]
fn update_workspace_on_server(&self, params: UpdateWorkspaceParams) -> Result<(), WorkspaceError> {
let (token, server) = self.token_with_server()?;
spawn(async move {
tokio::spawn(async move {
match server.update_workspace(&token, params).await {
Ok(_) => {},
Err(e) => {
@ -308,7 +320,7 @@ impl WorkspaceController {
workspace_id: workspace_id.to_string(),
};
let (token, server) = self.token_with_server()?;
spawn(async move {
tokio::spawn(async move {
match server.delete_workspace(&token, params).await {
Ok(_) => {},
Err(e) => {
@ -327,7 +339,7 @@ impl WorkspaceController {
let app_ctrl = self.app_controller.clone();
let view_ctrl = self.view_controller.clone();
let conn = self.database.db_connection()?;
spawn(async move {
tokio::spawn(async move {
// Opti: handle the error and retry?
let workspaces = server.read_workspace(&token, params).await?;
let _ = (&*conn).immediate_transaction::<_, WorkspaceError, _>(|| {

View File

@ -8,30 +8,40 @@ use flowy_workspace::{
#[tokio::test]
async fn workspace_read_all() {
let test = WorkspaceTest::new().await;
let workspace = read_workspace(&test.sdk, QueryWorkspaceRequest::new()).await.unwrap();
assert_eq!(test.workspace, workspace);
let workspace = read_workspace(&test.sdk, QueryWorkspaceRequest::new(None)).await;
assert_eq!(workspace.len(), 2);
}
#[tokio::test]
async fn workspace_read() {
let test = WorkspaceTest::new().await;
let request = QueryWorkspaceRequest::new().workspace_id(&test.workspace.id);
let workspace = read_workspace(&test.sdk, request).await.unwrap();
assert_eq!(test.workspace, workspace);
let request = QueryWorkspaceRequest::new(Some(test.workspace.id.clone()));
let workspace_from_db = read_workspace(&test.sdk, request)
.await
.drain(..1)
.collect::<Vec<Workspace>>()
.pop()
.unwrap();
assert_eq!(test.workspace, workspace_from_db);
}
#[tokio::test]
async fn workspace_create_with_apps() {
let test = WorkspaceTest::new().await;
let app = create_app(&test.sdk, "App A", "AppFlowy Github Project", &test.workspace.id).await;
let request = QueryWorkspaceRequest::new().workspace_id(&test.workspace.id);
let workspace_from_db = read_workspace(&test.sdk, request).await.unwrap();
let request = QueryWorkspaceRequest::new(Some(test.workspace.id.clone()));
let workspace_from_db = read_workspace(&test.sdk, request)
.await
.drain(..1)
.collect::<Vec<Workspace>>()
.pop()
.unwrap();
assert_eq!(&app, workspace_from_db.apps.first_or_crash());
}
#[tokio::test]
async fn workspace_create_with_invalid_name() {
for name in invalid_workspace_name_test_case() {
for (name, code) in invalid_workspace_name_test_case() {
let sdk = FlowyTest::setup().sdk;
let request = CreateWorkspaceRequest {
name,
@ -45,7 +55,7 @@ async fn workspace_create_with_invalid_name() {
.await
.error()
.code,
ErrorCode::WorkspaceNameInvalid.value()
code.value()
)
}
}
@ -53,7 +63,7 @@ async fn workspace_create_with_invalid_name() {
#[tokio::test]
async fn workspace_update_with_invalid_name() {
let sdk = FlowyTest::setup().sdk;
for name in invalid_workspace_name_test_case() {
for (name, code) in invalid_workspace_name_test_case() {
let request = CreateWorkspaceRequest {
name,
desc: "".to_owned(),
@ -66,7 +76,7 @@ async fn workspace_update_with_invalid_name() {
.await
.error()
.code,
ErrorCode::WorkspaceNameInvalid.value()
code.value()
)
}
}