From 403f343371b5277667dcd2d4635483993ea5afea Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 22 Apr 2025 10:15:19 +0800 Subject: [PATCH] chore: delete supabase test --- .../tests/database/supabase_test/helper.rs | 106 ---- .../tests/database/supabase_test/mod.rs | 2 - .../tests/database/supabase_test/test.rs | 108 ---- .../tests/document/supabase_test/edit_test.rs | 65 --- .../tests/document/supabase_test/file_test.rs | 118 ---- .../tests/document/supabase_test/helper.rs | 49 -- .../tests/document/supabase_test/mod.rs | 3 - .../tests/folder/supabase_test/helper.rs | 91 ---- .../tests/folder/supabase_test/mod.rs | 2 - .../tests/folder/supabase_test/test.rs | 122 ----- .../tests/user/supabase_test/auth_test.rs | 502 ------------------ .../supabase_test/history_user_db/README.md | 4 - .../history_user_db/workspace_sync.zip | Bin 44001 -> 0 bytes .../tests/user/supabase_test/mod.rs | 2 - .../user/supabase_test/workspace_test.rs | 43 -- 15 files changed, 1217 deletions(-) delete mode 100644 frontend/rust-lib/event-integration-test/tests/database/supabase_test/helper.rs delete mode 100644 frontend/rust-lib/event-integration-test/tests/database/supabase_test/mod.rs delete mode 100644 frontend/rust-lib/event-integration-test/tests/database/supabase_test/test.rs delete mode 100644 frontend/rust-lib/event-integration-test/tests/document/supabase_test/edit_test.rs delete mode 100644 frontend/rust-lib/event-integration-test/tests/document/supabase_test/file_test.rs delete mode 100644 frontend/rust-lib/event-integration-test/tests/document/supabase_test/helper.rs delete mode 100644 frontend/rust-lib/event-integration-test/tests/document/supabase_test/mod.rs delete mode 100644 frontend/rust-lib/event-integration-test/tests/folder/supabase_test/helper.rs delete mode 100644 frontend/rust-lib/event-integration-test/tests/folder/supabase_test/mod.rs delete mode 100644 frontend/rust-lib/event-integration-test/tests/folder/supabase_test/test.rs delete mode 100644 frontend/rust-lib/event-integration-test/tests/user/supabase_test/auth_test.rs delete mode 100644 frontend/rust-lib/event-integration-test/tests/user/supabase_test/history_user_db/README.md delete mode 100644 frontend/rust-lib/event-integration-test/tests/user/supabase_test/history_user_db/workspace_sync.zip delete mode 100644 frontend/rust-lib/event-integration-test/tests/user/supabase_test/mod.rs delete mode 100644 frontend/rust-lib/event-integration-test/tests/user/supabase_test/workspace_test.rs diff --git a/frontend/rust-lib/event-integration-test/tests/database/supabase_test/helper.rs b/frontend/rust-lib/event-integration-test/tests/database/supabase_test/helper.rs deleted file mode 100644 index c1874a5004..0000000000 --- a/frontend/rust-lib/event-integration-test/tests/database/supabase_test/helper.rs +++ /dev/null @@ -1,106 +0,0 @@ -use std::ops::Deref; - -use assert_json_diff::assert_json_eq; -use collab::core::collab::MutexCollab; -use collab::core::origin::CollabOrigin; -use collab::preclude::updates::decoder::Decode; -use collab::preclude::{Collab, JsonValue, Update}; -use collab_entity::CollabType; - -use event_integration_test::event_builder::EventBuilder; -use flowy_database2::entities::{DatabasePB, DatabaseViewIdPB, RepeatedDatabaseSnapshotPB}; -use flowy_database2::event_map::DatabaseEvent::*; -use flowy_folder::entities::ViewPB; - -use crate::util::FlowySupabaseTest; - -pub struct FlowySupabaseDatabaseTest { - pub uuid: String, - inner: FlowySupabaseTest, -} - -impl FlowySupabaseDatabaseTest { - #[allow(dead_code)] - pub async fn new_with_user(uuid: String) -> Option { - let inner = FlowySupabaseTest::new().await?; - inner.supabase_sign_up_with_uuid(&uuid, None).await.unwrap(); - Some(Self { uuid, inner }) - } - - pub async fn new_with_new_user() -> Option { - let inner = FlowySupabaseTest::new().await?; - let uuid = uuid::Uuid::new_v4().to_string(); - let _ = inner.supabase_sign_up_with_uuid(&uuid, None).await.unwrap(); - Some(Self { uuid, inner }) - } - - pub async fn create_database(&self) -> (ViewPB, DatabasePB) { - let current_workspace = self.inner.get_current_workspace().await; - let view = self - .inner - .create_grid(¤t_workspace.id, "my database".to_string(), vec![]) - .await; - let database = self.inner.get_database(&view.id).await; - (view, database) - } - - pub async fn get_collab_json(&self, database_id: &str) -> JsonValue { - let database_editor = self - .database_manager - .get_database(database_id) - .await - .unwrap(); - // let address = Arc::into_raw(database_editor.clone()); - let database = database_editor.get_mutex_database().lock(); - database.get_mutex_collab().to_json_value() - } - - pub async fn get_database_snapshots(&self, view_id: &str) -> RepeatedDatabaseSnapshotPB { - EventBuilder::new(self.inner.deref().clone()) - .event(GetDatabaseSnapshots) - .payload(DatabaseViewIdPB { - value: view_id.to_string(), - }) - .async_send() - .await - .parse::() - } - - pub async fn get_database_collab_update(&self, database_id: &str) -> Vec { - let workspace_id = self.user_manager.workspace_id().unwrap(); - let cloud_service = self.database_manager.get_cloud_service().clone(); - cloud_service - .get_database_object_doc_state(database_id, CollabType::Database, &workspace_id) - .await - .unwrap() - .unwrap() - } -} - -pub fn assert_database_collab_content( - database_id: &str, - collab_update: &[u8], - expected: JsonValue, -) { - let collab = MutexCollab::new(Collab::new_with_origin( - CollabOrigin::Server, - database_id, - vec![], - false, - )); - collab.lock().with_origin_transact_mut(|txn| { - let update = Update::decode_v1(collab_update).unwrap(); - txn.apply_update(update).unwrap(); - }); - - let json = collab.to_json_value(); - assert_json_eq!(json, expected); -} - -impl Deref for FlowySupabaseDatabaseTest { - type Target = FlowySupabaseTest; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} diff --git a/frontend/rust-lib/event-integration-test/tests/database/supabase_test/mod.rs b/frontend/rust-lib/event-integration-test/tests/database/supabase_test/mod.rs deleted file mode 100644 index 05fa1b00ed..0000000000 --- a/frontend/rust-lib/event-integration-test/tests/database/supabase_test/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod helper; -mod test; diff --git a/frontend/rust-lib/event-integration-test/tests/database/supabase_test/test.rs b/frontend/rust-lib/event-integration-test/tests/database/supabase_test/test.rs deleted file mode 100644 index 537cdf80d8..0000000000 --- a/frontend/rust-lib/event-integration-test/tests/database/supabase_test/test.rs +++ /dev/null @@ -1,108 +0,0 @@ -use std::time::Duration; - -use flowy_database2::entities::{ - DatabaseSnapshotStatePB, DatabaseSyncState, DatabaseSyncStatePB, FieldChangesetPB, FieldType, -}; -use flowy_database2::notification::DatabaseNotification::DidUpdateDatabaseSnapshotState; - -use crate::database::supabase_test::helper::{ - assert_database_collab_content, FlowySupabaseDatabaseTest, -}; -use crate::util::receive_with_timeout; - -#[tokio::test] -async fn supabase_initial_database_snapshot_test() { - if let Some(test) = FlowySupabaseDatabaseTest::new_with_new_user().await { - let (view, database) = test.create_database().await; - let rx = test - .notification_sender - .subscribe::(&database.id, DidUpdateDatabaseSnapshotState); - - receive_with_timeout(rx, Duration::from_secs(30)) - .await - .unwrap(); - - let expected = test.get_collab_json(&database.id).await; - let snapshots = test.get_database_snapshots(&view.id).await; - assert_eq!(snapshots.items.len(), 1); - assert_database_collab_content(&database.id, &snapshots.items[0].data, expected); - } -} - -#[tokio::test] -async fn supabase_edit_database_test() { - if let Some(test) = FlowySupabaseDatabaseTest::new_with_new_user().await { - let (view, database) = test.create_database().await; - let existing_fields = test.get_all_database_fields(&view.id).await; - for field in existing_fields.items { - if !field.is_primary { - test.delete_field(&view.id, &field.id).await; - } - } - - let field = test.create_field(&view.id, FieldType::Checklist).await; - test - .update_field(FieldChangesetPB { - field_id: field.id.clone(), - view_id: view.id.clone(), - name: Some("hello world".to_string()), - ..Default::default() - }) - .await; - - // wait all updates are send to the remote - let rx = test - .notification_sender - .subscribe_with_condition::(&database.id, |pb| { - pb.value == DatabaseSyncState::SyncFinished - }); - receive_with_timeout(rx, Duration::from_secs(30)) - .await - .unwrap(); - - assert_eq!(test.get_all_database_fields(&view.id).await.items.len(), 2); - let expected = test.get_collab_json(&database.id).await; - let update = test.get_database_collab_update(&database.id).await; - assert_database_collab_content(&database.id, &update, expected); - } -} - -// #[tokio::test] -// async fn cloud_test_supabase_login_sync_database_test() { -// if let Some(test) = FlowySupabaseDatabaseTest::new_with_new_user().await { -// let uuid = test.uuid.clone(); -// let (view, database) = test.create_database().await; -// // wait all updates are send to the remote -// let mut rx = test -// .notification_sender -// .subscribe_with_condition::(&database.id, |pb| pb.is_finish); -// receive_with_timeout(&mut rx, Duration::from_secs(30)) -// .await -// .unwrap(); -// let expected = test.get_collab_json(&database.id).await; -// test.sign_out().await; -// // Drop the test will cause the test resources to be dropped, which will -// // delete the user data folder. -// drop(test); -// -// let new_test = FlowySupabaseDatabaseTest::new_with_user(uuid) -// .await -// .unwrap(); -// // let actual = new_test.get_collab_json(&database.id).await; -// // assert_json_eq!(actual, json!("")); -// -// new_test.open_database(&view.id).await; -// -// // wait all updates are synced from the remote -// let mut rx = new_test -// .notification_sender -// .subscribe_with_condition::(&database.id, |pb| pb.is_finish); -// receive_with_timeout(&mut rx, Duration::from_secs(30)) -// .await -// .unwrap(); -// -// // when the new sync is finished, the database should be the same as the old one -// let actual = new_test.get_collab_json(&database.id).await; -// assert_json_eq!(actual, expected); -// } -// } diff --git a/frontend/rust-lib/event-integration-test/tests/document/supabase_test/edit_test.rs b/frontend/rust-lib/event-integration-test/tests/document/supabase_test/edit_test.rs deleted file mode 100644 index d05e1ef95c..0000000000 --- a/frontend/rust-lib/event-integration-test/tests/document/supabase_test/edit_test.rs +++ /dev/null @@ -1,65 +0,0 @@ -use std::time::Duration; - -use event_integration_test::document_event::assert_document_data_equal; -use flowy_document::entities::{DocumentSyncState, DocumentSyncStatePB}; - -use crate::document::supabase_test::helper::FlowySupabaseDocumentTest; -use crate::util::receive_with_timeout; - -#[tokio::test] -async fn supabase_document_edit_sync_test() { - if let Some(test) = FlowySupabaseDocumentTest::new().await { - let view = test.create_document().await; - let document_id = view.id.clone(); - - let cloned_test = test.clone(); - let cloned_document_id = document_id.clone(); - test.appflowy_core.dispatcher().spawn(async move { - cloned_test - .insert_document_text(&cloned_document_id, "hello world", 0) - .await; - }); - - // wait all update are send to the remote - let rx = test - .notification_sender - .subscribe_with_condition::(&document_id, |pb| { - pb.value != DocumentSyncState::Syncing - }); - receive_with_timeout(rx, Duration::from_secs(30)) - .await - .unwrap(); - - let document_data = test.get_document_data(&document_id).await; - let update = test.get_document_doc_state(&document_id).await; - assert_document_data_equal(&update, &document_id, document_data); - } -} - -#[tokio::test] -async fn supabase_document_edit_sync_test2() { - if let Some(test) = FlowySupabaseDocumentTest::new().await { - let view = test.create_document().await; - let document_id = view.id.clone(); - - for i in 0..10 { - test - .insert_document_text(&document_id, "hello world", i) - .await; - } - - // wait all update are send to the remote - let rx = test - .notification_sender - .subscribe_with_condition::(&document_id, |pb| { - pb.value != DocumentSyncState::Syncing - }); - receive_with_timeout(rx, Duration::from_secs(30)) - .await - .unwrap(); - - let document_data = test.get_document_data(&document_id).await; - let update = test.get_document_doc_state(&document_id).await; - assert_document_data_equal(&update, &document_id, document_data); - } -} diff --git a/frontend/rust-lib/event-integration-test/tests/document/supabase_test/file_test.rs b/frontend/rust-lib/event-integration-test/tests/document/supabase_test/file_test.rs deleted file mode 100644 index e73273cde6..0000000000 --- a/frontend/rust-lib/event-integration-test/tests/document/supabase_test/file_test.rs +++ /dev/null @@ -1,118 +0,0 @@ -// use std::fs::File; -// use std::io::{Cursor, Read}; -// use std::path::Path; -// -// use uuid::Uuid; -// use zip::ZipArchive; -// -// use flowy_storage::StorageObject; -// -// use crate::document::supabase_test::helper::FlowySupabaseDocumentTest; -// -// #[tokio::test] -// async fn supabase_document_upload_text_file_test() { -// if let Some(test) = FlowySupabaseDocumentTest::new().await { -// let workspace_id = test.get_current_workspace().await.id; -// let storage_service = test -// .document_manager -// .get_file_storage_service() -// .upgrade() -// .unwrap(); -// -// let object = StorageObject::from_bytes( -// &workspace_id, -// &Uuid::new_v4().to_string(), -// "hello world".as_bytes(), -// "text/plain".to_string(), -// ); -// -// let url = storage_service.create_object(object).await.unwrap(); -// -// let bytes = storage_service -// .get_object(url.clone()) -// .await -// .unwrap(); -// let s = String::from_utf8(bytes.to_vec()).unwrap(); -// assert_eq!(s, "hello world"); -// -// // Delete the text file -// let _ = storage_service.delete_object(url).await; -// } -// } -// -// #[tokio::test] -// async fn supabase_document_upload_zip_file_test() { -// if let Some(test) = FlowySupabaseDocumentTest::new().await { -// let workspace_id = test.get_current_workspace().await.id; -// let storage_service = test -// .document_manager -// .get_file_storage_service() -// .upgrade() -// .unwrap(); -// -// // Upload zip file -// let object = StorageObject::from_file( -// &workspace_id, -// &Uuid::new_v4().to_string(), -// "./tests/asset/test.txt.zip", -// ); -// let url = storage_service.create_object(object).await.unwrap(); -// -// // Read zip file -// let zip_data = storage_service -// .get_object(url.clone()) -// .await -// .unwrap(); -// let reader = Cursor::new(zip_data); -// let mut archive = ZipArchive::new(reader).unwrap(); -// for i in 0..archive.len() { -// let mut file = archive.by_index(i).unwrap(); -// let name = file.name().to_string(); -// let mut out = Vec::new(); -// file.read_to_end(&mut out).unwrap(); -// -// if name.starts_with("__MACOSX/") { -// continue; -// } -// assert_eq!(name, "test.txt"); -// assert_eq!(String::from_utf8(out).unwrap(), "hello world"); -// } -// -// // Delete the zip file -// let _ = storage_service.delete_object(url).await; -// } -// } -// #[tokio::test] -// async fn supabase_document_upload_image_test() { -// if let Some(test) = FlowySupabaseDocumentTest::new().await { -// let workspace_id = test.get_current_workspace().await.id; -// let storage_service = test -// .document_manager -// .get_file_storage_service() -// .upgrade() -// .unwrap(); -// -// // Upload zip file -// let object = StorageObject::from_file( -// &workspace_id, -// &Uuid::new_v4().to_string(), -// "./tests/asset/logo.png", -// ); -// let url = storage_service.create_object(object).await.unwrap(); -// -// let image_data = storage_service -// .get_object(url.clone()) -// .await -// .unwrap(); -// -// // Read the image file -// let mut file = File::open(Path::new("./tests/asset/logo.png")).unwrap(); -// let mut local_data = Vec::new(); -// file.read_to_end(&mut local_data).unwrap(); -// -// assert_eq!(image_data, local_data); -// -// // Delete the image -// let _ = storage_service.delete_object(url).await; -// } -// } diff --git a/frontend/rust-lib/event-integration-test/tests/document/supabase_test/helper.rs b/frontend/rust-lib/event-integration-test/tests/document/supabase_test/helper.rs deleted file mode 100644 index 07ff2d96fe..0000000000 --- a/frontend/rust-lib/event-integration-test/tests/document/supabase_test/helper.rs +++ /dev/null @@ -1,49 +0,0 @@ -use std::ops::Deref; - -use event_integration_test::event_builder::EventBuilder; -use flowy_document::entities::{OpenDocumentPayloadPB, RepeatedDocumentSnapshotMetaPB}; -use flowy_document::event_map::DocumentEvent::GetDocumentSnapshotMeta; -use flowy_folder::entities::ViewPB; - -use crate::util::FlowySupabaseTest; - -pub struct FlowySupabaseDocumentTest { - inner: FlowySupabaseTest, -} - -impl FlowySupabaseDocumentTest { - pub async fn new() -> Option { - let inner = FlowySupabaseTest::new().await?; - let uuid = uuid::Uuid::new_v4().to_string(); - let _ = inner.supabase_sign_up_with_uuid(&uuid, None).await; - Some(Self { inner }) - } - - pub async fn create_document(&self) -> ViewPB { - let current_workspace = self.inner.get_current_workspace().await; - self - .inner - .create_and_open_document(¤t_workspace.id, "my document".to_string(), vec![]) - .await - } - - #[allow(dead_code)] - pub async fn get_document_snapshots(&self, view_id: &str) -> RepeatedDocumentSnapshotMetaPB { - EventBuilder::new(self.inner.deref().clone()) - .event(GetDocumentSnapshotMeta) - .payload(OpenDocumentPayloadPB { - document_id: view_id.to_string(), - }) - .async_send() - .await - .parse::() - } -} - -impl Deref for FlowySupabaseDocumentTest { - type Target = FlowySupabaseTest; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} diff --git a/frontend/rust-lib/event-integration-test/tests/document/supabase_test/mod.rs b/frontend/rust-lib/event-integration-test/tests/document/supabase_test/mod.rs deleted file mode 100644 index 165f5fdfc0..0000000000 --- a/frontend/rust-lib/event-integration-test/tests/document/supabase_test/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod edit_test; -mod file_test; -mod helper; diff --git a/frontend/rust-lib/event-integration-test/tests/folder/supabase_test/helper.rs b/frontend/rust-lib/event-integration-test/tests/folder/supabase_test/helper.rs deleted file mode 100644 index a1179ce6cc..0000000000 --- a/frontend/rust-lib/event-integration-test/tests/folder/supabase_test/helper.rs +++ /dev/null @@ -1,91 +0,0 @@ -use std::ops::Deref; - -use assert_json_diff::assert_json_eq; -use collab::core::collab::MutexCollab; -use collab::core::origin::CollabOrigin; -use collab::preclude::updates::decoder::Decode; -use collab::preclude::{Collab, JsonValue, Update}; -use collab_entity::CollabType; -use collab_folder::FolderData; - -use event_integration_test::event_builder::EventBuilder; -use flowy_folder::entities::{FolderSnapshotPB, RepeatedFolderSnapshotPB, WorkspaceIdPB}; -use flowy_folder::event_map::FolderEvent::GetFolderSnapshots; - -use crate::util::FlowySupabaseTest; - -pub struct FlowySupabaseFolderTest { - inner: FlowySupabaseTest, -} - -impl FlowySupabaseFolderTest { - pub async fn new() -> Option { - let inner = FlowySupabaseTest::new().await?; - let uuid = uuid::Uuid::new_v4().to_string(); - let _ = inner.supabase_sign_up_with_uuid(&uuid, None).await; - Some(Self { inner }) - } - - pub async fn get_collab_json(&self) -> JsonValue { - let folder = self.folder_manager.get_mutex_folder().lock(); - folder.as_ref().unwrap().to_json_value() - } - - pub async fn get_local_folder_data(&self) -> FolderData { - let folder = self.folder_manager.get_mutex_folder().lock(); - folder.as_ref().unwrap().get_folder_data().unwrap() - } - - pub async fn get_folder_snapshots(&self, workspace_id: &str) -> Vec { - EventBuilder::new(self.inner.deref().clone()) - .event(GetFolderSnapshots) - .payload(WorkspaceIdPB { - value: workspace_id.to_string(), - }) - .async_send() - .await - .parse::() - .items - } - - pub async fn get_collab_update(&self, workspace_id: &str) -> Vec { - let cloud_service = self.folder_manager.get_cloud_service().clone(); - cloud_service - .get_folder_doc_state( - workspace_id, - self.user_manager.user_id().unwrap(), - CollabType::Folder, - workspace_id, - ) - .await - .unwrap() - } -} - -pub fn assert_folder_collab_content(workspace_id: &str, collab_update: &[u8], expected: JsonValue) { - if collab_update.is_empty() { - panic!("collab update is empty"); - } - - let collab = MutexCollab::new(Collab::new_with_origin( - CollabOrigin::Server, - workspace_id, - vec![], - false, - )); - collab.lock().with_origin_transact_mut(|txn| { - let update = Update::decode_v1(collab_update).unwrap(); - txn.apply_update(update).unwrap(); - }); - - let json = collab.to_json_value(); - assert_json_eq!(json["folder"], expected); -} - -impl Deref for FlowySupabaseFolderTest { - type Target = FlowySupabaseTest; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} diff --git a/frontend/rust-lib/event-integration-test/tests/folder/supabase_test/mod.rs b/frontend/rust-lib/event-integration-test/tests/folder/supabase_test/mod.rs deleted file mode 100644 index 05fa1b00ed..0000000000 --- a/frontend/rust-lib/event-integration-test/tests/folder/supabase_test/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod helper; -mod test; diff --git a/frontend/rust-lib/event-integration-test/tests/folder/supabase_test/test.rs b/frontend/rust-lib/event-integration-test/tests/folder/supabase_test/test.rs deleted file mode 100644 index 5f6a50988a..0000000000 --- a/frontend/rust-lib/event-integration-test/tests/folder/supabase_test/test.rs +++ /dev/null @@ -1,122 +0,0 @@ -use std::time::Duration; - -use assert_json_diff::assert_json_eq; -use serde_json::json; - -use flowy_folder::entities::{FolderSnapshotStatePB, FolderSyncStatePB}; -use flowy_folder::notification::FolderNotification::DidUpdateFolderSnapshotState; - -use crate::folder::supabase_test::helper::{assert_folder_collab_content, FlowySupabaseFolderTest}; -use crate::util::{get_folder_data_from_server, receive_with_timeout}; - -#[tokio::test] -async fn supabase_encrypt_folder_test() { - if let Some(test) = FlowySupabaseFolderTest::new().await { - let uid = test.user_manager.user_id().unwrap(); - let secret = test.enable_encryption().await; - - let local_folder_data = test.get_local_folder_data().await; - let workspace_id = test.get_current_workspace().await.id; - let remote_folder_data = get_folder_data_from_server(&uid, &workspace_id, Some(secret)) - .await - .unwrap() - .unwrap(); - - assert_json_eq!(json!(local_folder_data), json!(remote_folder_data)); - } -} - -#[tokio::test] -async fn supabase_decrypt_folder_data_test() { - if let Some(test) = FlowySupabaseFolderTest::new().await { - let uid = test.user_manager.user_id().unwrap(); - let secret = Some(test.enable_encryption().await); - let workspace_id = test.get_current_workspace().await.id; - test - .create_view(&workspace_id, "encrypt view".to_string()) - .await; - - let rx = test - .notification_sender - .subscribe_with_condition::(&workspace_id, |pb| pb.is_finish); - - receive_with_timeout(rx, Duration::from_secs(10)) - .await - .unwrap(); - let folder_data = get_folder_data_from_server(&uid, &workspace_id, secret) - .await - .unwrap() - .unwrap(); - assert_eq!(folder_data.views.len(), 2); - assert_eq!(folder_data.views[1].name, "encrypt view"); - } -} - -#[tokio::test] -#[should_panic] -async fn supabase_decrypt_with_invalid_secret_folder_data_test() { - if let Some(test) = FlowySupabaseFolderTest::new().await { - let uid = test.user_manager.user_id().unwrap(); - let _ = Some(test.enable_encryption().await); - let workspace_id = test.get_current_workspace().await.id; - test - .create_view(&workspace_id, "encrypt view".to_string()) - .await; - let rx = test - .notification_sender - .subscribe_with_condition::(&workspace_id, |pb| pb.is_finish); - receive_with_timeout(rx, Duration::from_secs(10)) - .await - .unwrap(); - - let _ = get_folder_data_from_server(&uid, &workspace_id, Some("invalid secret".to_string())) - .await - .unwrap(); - } -} -#[tokio::test] -async fn supabase_folder_snapshot_test() { - if let Some(test) = FlowySupabaseFolderTest::new().await { - let workspace_id = test.get_current_workspace().await.id; - let rx = test - .notification_sender - .subscribe::(&workspace_id, DidUpdateFolderSnapshotState); - receive_with_timeout(rx, Duration::from_secs(10)) - .await - .unwrap(); - - let expected = test.get_collab_json().await; - let snapshots = test.get_folder_snapshots(&workspace_id).await; - assert_eq!(snapshots.len(), 1); - assert_folder_collab_content(&workspace_id, &snapshots[0].data, expected); - } -} - -#[tokio::test] -async fn supabase_initial_folder_snapshot_test2() { - if let Some(test) = FlowySupabaseFolderTest::new().await { - let workspace_id = test.get_current_workspace().await.id; - - test - .create_view(&workspace_id, "supabase test view1".to_string()) - .await; - test - .create_view(&workspace_id, "supabase test view2".to_string()) - .await; - test - .create_view(&workspace_id, "supabase test view3".to_string()) - .await; - - let rx = test - .notification_sender - .subscribe_with_condition::(&workspace_id, |pb| pb.is_finish); - - receive_with_timeout(rx, Duration::from_secs(10)) - .await - .unwrap(); - - let expected = test.get_collab_json().await; - let update = test.get_collab_update(&workspace_id).await; - assert_folder_collab_content(&workspace_id, &update, expected); - } -} diff --git a/frontend/rust-lib/event-integration-test/tests/user/supabase_test/auth_test.rs b/frontend/rust-lib/event-integration-test/tests/user/supabase_test/auth_test.rs deleted file mode 100644 index 1b6d5f9cc6..0000000000 --- a/frontend/rust-lib/event-integration-test/tests/user/supabase_test/auth_test.rs +++ /dev/null @@ -1,502 +0,0 @@ -use std::collections::HashMap; - -use assert_json_diff::assert_json_eq; -use collab_database::rows::database_row_document_id_from_row_id; -use collab_document::blocks::DocumentData; -use collab_entity::CollabType; -use collab_folder::FolderData; -use nanoid::nanoid; -use serde_json::json; - -use event_integration_test::document::document_event::DocumentEventTest; -use event_integration_test::event_builder::EventBuilder; -use event_integration_test::EventIntegrationTest; -use flowy_core::DEFAULT_NAME; -use flowy_encrypt::decrypt_text; -use flowy_server::supabase::define::{USER_DEVICE_ID, USER_EMAIL, USER_UUID}; -use flowy_user::entities::{ - AuthenticatorPB, OauthSignInPB, UpdateUserProfilePayloadPB, UserProfilePB, -}; -use flowy_user::errors::ErrorCode; -use flowy_user::event_map::UserEvent::*; - -use crate::util::*; - -#[tokio::test] -async fn third_party_sign_up_test() { - if get_supabase_config().is_some() { - let test = EventIntegrationTest::new().await; - let mut map = HashMap::new(); - map.insert(USER_UUID.to_string(), uuid::Uuid::new_v4().to_string()); - map.insert( - USER_EMAIL.to_string(), - format!("{}@appflowy.io", nanoid!(6)), - ); - map.insert(USER_DEVICE_ID.to_string(), uuid::Uuid::new_v4().to_string()); - let payload = OauthSignInPB { - map, - authenticator: AuthenticatorPB::Supabase, - }; - - let response = EventBuilder::new(test.clone()) - .event(OauthSignIn) - .payload(payload) - .async_send() - .await - .parse::(); - dbg!(&response); - } -} - -#[tokio::test] -async fn third_party_sign_up_with_encrypt_test() { - if get_supabase_config().is_some() { - let test = EventIntegrationTest::new().await; - test.supabase_party_sign_up().await; - let user_profile = test.get_user_profile().await.unwrap(); - assert!(user_profile.encryption_sign.is_empty()); - - let secret = test.enable_encryption().await; - let user_profile = test.get_user_profile().await.unwrap(); - assert!(!user_profile.encryption_sign.is_empty()); - - let decryption_sign = decrypt_text(user_profile.encryption_sign, &secret).unwrap(); - assert_eq!(decryption_sign, user_profile.id.to_string()); - } -} - -#[tokio::test] -async fn third_party_sign_up_with_duplicated_uuid() { - if get_supabase_config().is_some() { - let test = EventIntegrationTest::new().await; - let email = format!("{}@appflowy.io", nanoid!(6)); - let mut map = HashMap::new(); - map.insert(USER_UUID.to_string(), uuid::Uuid::new_v4().to_string()); - map.insert(USER_EMAIL.to_string(), email.clone()); - map.insert(USER_DEVICE_ID.to_string(), uuid::Uuid::new_v4().to_string()); - - let response_1 = EventBuilder::new(test.clone()) - .event(OauthSignIn) - .payload(OauthSignInPB { - map: map.clone(), - authenticator: AuthenticatorPB::Supabase, - }) - .async_send() - .await - .parse::(); - dbg!(&response_1); - - let response_2 = EventBuilder::new(test.clone()) - .event(OauthSignIn) - .payload(OauthSignInPB { - map: map.clone(), - authenticator: AuthenticatorPB::Supabase, - }) - .async_send() - .await - .parse::(); - assert_eq!(response_1, response_2); - }; -} - -#[tokio::test] -async fn third_party_sign_up_with_duplicated_email() { - if get_supabase_config().is_some() { - let test = EventIntegrationTest::new().await; - let email = format!("{}@appflowy.io", nanoid!(6)); - test - .supabase_sign_up_with_uuid(&uuid::Uuid::new_v4().to_string(), Some(email.clone())) - .await - .unwrap(); - let error = test - .supabase_sign_up_with_uuid(&uuid::Uuid::new_v4().to_string(), Some(email.clone())) - .await - .err() - .unwrap(); - assert_eq!(error.code, ErrorCode::Conflict); - }; -} - -#[tokio::test] -async fn sign_up_as_guest_and_then_update_to_new_cloud_user_test() { - if get_supabase_config().is_some() { - let test = EventIntegrationTest::new_anon().await; - let old_views = test - .folder_manager - .get_current_workspace_public_views() - .await - .unwrap(); - let old_workspace = test.folder_manager.get_current_workspace().await.unwrap(); - - let uuid = uuid::Uuid::new_v4().to_string(); - test.supabase_sign_up_with_uuid(&uuid, None).await.unwrap(); - let new_views = test - .folder_manager - .get_current_workspace_public_views() - .await - .unwrap(); - let new_workspace = test.folder_manager.get_current_workspace().await.unwrap(); - - assert_eq!(old_views.len(), new_views.len()); - assert_eq!(old_workspace.name, new_workspace.name); - assert_eq!(old_workspace.views.len(), new_workspace.views.len()); - for (index, view) in old_views.iter().enumerate() { - assert_eq!(view.name, new_views[index].name); - assert_eq!(view.layout, new_views[index].layout); - assert_eq!(view.create_time, new_views[index].create_time); - } - } -} - -#[tokio::test] -async fn sign_up_as_guest_and_then_update_to_existing_cloud_user_test() { - if get_supabase_config().is_some() { - let test = EventIntegrationTest::new_anon().await; - let uuid = uuid::Uuid::new_v4().to_string(); - - let email = format!("{}@appflowy.io", nanoid!(6)); - // The workspace of the guest will be migrated to the new user with given uuid - let _user_profile = test - .supabase_sign_up_with_uuid(&uuid, Some(email.clone())) - .await - .unwrap(); - let old_cloud_workspace = test.folder_manager.get_current_workspace().await.unwrap(); - let old_cloud_views = test - .folder_manager - .get_current_workspace_public_views() - .await - .unwrap(); - assert_eq!(old_cloud_views.len(), 1); - assert_eq!(old_cloud_views.first().unwrap().child_views.len(), 1); - - // sign out and then sign in as a guest - test.sign_out().await; - - let _sign_up_context = test.sign_up_as_anon().await; - let new_workspace = test.folder_manager.get_current_workspace().await.unwrap(); - test - .create_view(&new_workspace.id, "new workspace child view".to_string()) - .await; - let new_workspace = test.folder_manager.get_current_workspace().await.unwrap(); - assert_eq!(new_workspace.views.len(), 2); - - // upload to cloud user with given uuid. This time the workspace of the guest will not be merged - // because the cloud user already has a workspace - test - .supabase_sign_up_with_uuid(&uuid, Some(email)) - .await - .unwrap(); - let new_cloud_workspace = test.folder_manager.get_current_workspace().await.unwrap(); - let new_cloud_views = test - .folder_manager - .get_current_workspace_public_views() - .await - .unwrap(); - assert_eq!(new_cloud_workspace, old_cloud_workspace); - assert_eq!(new_cloud_views, old_cloud_views); - } -} - -#[tokio::test] -async fn get_user_profile_test() { - if let Some(test) = FlowySupabaseTest::new().await { - let uuid = uuid::Uuid::new_v4().to_string(); - test.supabase_sign_up_with_uuid(&uuid, None).await.unwrap(); - - let result = test.get_user_profile().await; - assert!(result.is_ok()); - } -} - -#[tokio::test] -async fn update_user_profile_test() { - if let Some(test) = FlowySupabaseTest::new().await { - let uuid = uuid::Uuid::new_v4().to_string(); - let profile = test.supabase_sign_up_with_uuid(&uuid, None).await.unwrap(); - test - .update_user_profile(UpdateUserProfilePayloadPB::new(profile.id).name("lucas")) - .await; - - let new_profile = test.get_user_profile().await.unwrap(); - assert_eq!(new_profile.name, "lucas") - } -} - -#[tokio::test] -async fn update_user_profile_with_existing_email_test() { - if let Some(test) = FlowySupabaseTest::new().await { - let email = format!("{}@appflowy.io", nanoid!(6)); - let _ = test - .supabase_sign_up_with_uuid(&uuid::Uuid::new_v4().to_string(), Some(email.clone())) - .await; - - let profile = test - .supabase_sign_up_with_uuid( - &uuid::Uuid::new_v4().to_string(), - Some(format!("{}@appflowy.io", nanoid!(6))), - ) - .await - .unwrap(); - let error = test - .update_user_profile( - UpdateUserProfilePayloadPB::new(profile.id) - .name("lucas") - .email(&email), - ) - .await - .unwrap(); - assert_eq!(error.code, ErrorCode::Conflict); - } -} - -#[tokio::test] -async fn migrate_anon_document_on_cloud_signup() { - if get_supabase_config().is_some() { - let test = EventIntegrationTest::new().await; - let user_profile = test.sign_up_as_anon().await.user_profile; - - let view = test - .create_view(&user_profile.workspace_id, "My first view".to_string()) - .await; - let document_event = DocumentEventTest::new_with_core(test.clone()); - let block_id = document_event - .insert_index(&view.id, "hello world", 1, None) - .await; - - let _ = test.supabase_party_sign_up().await; - - let workspace_id = test.user_manager.workspace_id().unwrap(); - // After sign up, the documents should be migrated to the cloud - // So, we can get the document data from the cloud - let data: DocumentData = test - .document_manager - .get_cloud_service() - .get_document_data(&view.id, &workspace_id) - .await - .unwrap() - .unwrap(); - let block = data.blocks.get(&block_id).unwrap(); - assert_json_eq!( - block.data, - json!({ - "delta": [ - { - "insert": "hello world" - } - ] - }) - ); - } -} - -#[tokio::test] -async fn migrate_anon_data_on_cloud_signup() { - if get_supabase_config().is_some() { - let (cleaner, user_db_path) = unzip( - "./tests/user/supabase_test/history_user_db", - "workspace_sync", - ) - .unwrap(); - let test = - EventIntegrationTest::new_with_user_data_path(user_db_path, DEFAULT_NAME.to_string()).await; - let user_profile = test.supabase_party_sign_up().await; - - // Get the folder data from remote - let folder_data: FolderData = test - .folder_manager - .get_cloud_service() - .get_folder_data(&user_profile.workspace_id, &user_profile.id) - .await - .unwrap() - .unwrap(); - - let expected_folder_data = expected_workspace_sync_folder_data(); - assert_eq!(folder_data.views.len(), expected_folder_data.views.len()); - - // After migration, the ids of the folder_data should be different from the expected_folder_data - for i in 0..folder_data.views.len() { - let left_view = &folder_data.views[i]; - let right_view = &expected_folder_data.views[i]; - assert_ne!(left_view.id, right_view.id); - assert_ne!(left_view.parent_view_id, right_view.parent_view_id); - assert_eq!(left_view.name, right_view.name); - } - - assert_ne!(folder_data.workspace.id, expected_folder_data.workspace.id); - assert_ne!(folder_data.current_view, expected_folder_data.current_view); - - let database_views = folder_data - .views - .iter() - .filter(|view| view.layout.is_database()) - .collect::>(); - - // Try to load the database from the cloud. - for (i, database_view) in database_views.iter().enumerate() { - let cloud_service = test.database_manager.get_cloud_service(); - let database_id = test - .database_manager - .get_database_id_with_view_id(&database_view.id) - .await - .unwrap(); - let editor = test - .database_manager - .get_database(&database_id) - .await - .unwrap(); - - // The database view setting should be loaded by the view id - let _ = editor - .get_database_view_setting(&database_view.id) - .await - .unwrap(); - - let rows = editor.get_rows(&database_view.id).await.unwrap(); - assert_eq!(rows.len(), 3); - - let workspace_id = test.user_manager.workspace_id().unwrap(); - if i == 0 { - let first_row = rows.first().unwrap().as_ref(); - let icon_url = first_row.meta.icon_url.clone().unwrap(); - assert_eq!(icon_url, "😄"); - - let document_id = database_row_document_id_from_row_id(&first_row.row.id); - let document_data: DocumentData = test - .document_manager - .get_cloud_service() - .get_document_data(&document_id, &workspace_id) - .await - .unwrap() - .unwrap(); - - let editor = test - .document_manager - .get_document(&document_id) - .await - .unwrap(); - let expected_document_data = editor.lock().get_document_data().unwrap(); - - // let expected_document_data = test - // .document_manager - // .get_document_data(&document_id) - // .await - // .unwrap(); - assert_eq!(document_data, expected_document_data); - let json = json!(document_data); - assert_eq!( - json["blocks"]["LPMpo0Qaab"]["data"]["delta"][0]["insert"], - json!("Row document") - ); - } - assert!(cloud_service - .get_database_object_doc_state(&database_id, CollabType::Database, &workspace_id) - .await - .is_ok()); - } - - drop(cleaner); - } -} - -fn expected_workspace_sync_folder_data() -> FolderData { - serde_json::from_value::(json!({ - "current_view": "e0811131-9928-4541-a174-20b7553d9e4c", - "current_workspace_id": "8df7f755-fa5d-480e-9f8e-48ea0fed12b3", - "views": [ - { - "children": { - "items": [ - { - "id": "e0811131-9928-4541-a174-20b7553d9e4c" - }, - { - "id": "53333949-c262-447b-8597-107589697059" - } - ] - }, - "created_at": 1693147093, - "desc": "", - "icon": null, - "id": "e203afb3-de5d-458a-8380-33cd788a756e", - "is_favorite": false, - "layout": 0, - "name": "⭐️ Getting started", - "parent_view_id": "8df7f755-fa5d-480e-9f8e-48ea0fed12b3" - }, - { - "children": { - "items": [ - { - "id": "11c697ba-5ed1-41c0-adfc-576db28ad27b" - }, - { - "id": "4a5c25e2-a734-440c-973b-4c0e7ab0039c" - } - ] - }, - "created_at": 1693147096, - "desc": "", - "icon": null, - "id": "e0811131-9928-4541-a174-20b7553d9e4c", - "is_favorite": false, - "layout": 1, - "name": "database", - "parent_view_id": "e203afb3-de5d-458a-8380-33cd788a756e" - }, - { - "children": { - "items": [] - }, - "created_at": 1693147124, - "desc": "", - "icon": null, - "id": "11c697ba-5ed1-41c0-adfc-576db28ad27b", - "is_favorite": false, - "layout": 3, - "name": "calendar", - "parent_view_id": "e0811131-9928-4541-a174-20b7553d9e4c" - }, - { - "children": { - "items": [] - }, - "created_at": 1693147125, - "desc": "", - "icon": null, - "id": "4a5c25e2-a734-440c-973b-4c0e7ab0039c", - "is_favorite": false, - "layout": 2, - "name": "board", - "parent_view_id": "e0811131-9928-4541-a174-20b7553d9e4c" - }, - { - "children": { - "items": [] - }, - "created_at": 1693147133, - "desc": "", - "icon": null, - "id": "53333949-c262-447b-8597-107589697059", - "is_favorite": false, - "layout": 0, - "name": "document", - "parent_view_id": "e203afb3-de5d-458a-8380-33cd788a756e" - } - ], - "workspaces": [ - { - "child_views": { - "items": [ - { - "id": "e203afb3-de5d-458a-8380-33cd788a756e" - } - ] - }, - "created_at": 1693147093, - "id": "8df7f755-fa5d-480e-9f8e-48ea0fed12b3", - "name": "Workspace" - } - ] - })) - .unwrap() -} diff --git a/frontend/rust-lib/event-integration-test/tests/user/supabase_test/history_user_db/README.md b/frontend/rust-lib/event-integration-test/tests/user/supabase_test/history_user_db/README.md deleted file mode 100644 index 426255b00d..0000000000 --- a/frontend/rust-lib/event-integration-test/tests/user/supabase_test/history_user_db/README.md +++ /dev/null @@ -1,4 +0,0 @@ - -## Don't modify the zip files in this folder - -The zip files in this folder are used for integration tests. If the tests fail, it means users upgrading to this version of AppFlowy will encounter issues \ No newline at end of file diff --git a/frontend/rust-lib/event-integration-test/tests/user/supabase_test/history_user_db/workspace_sync.zip b/frontend/rust-lib/event-integration-test/tests/user/supabase_test/history_user_db/workspace_sync.zip deleted file mode 100644 index 6fd5ca087169d72d4edb9ec3edc8f6da927077c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44001 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 RU*hL4JVXG1(xjKG{|^(kLQDVv diff --git a/frontend/rust-lib/event-integration-test/tests/user/supabase_test/mod.rs b/frontend/rust-lib/event-integration-test/tests/user/supabase_test/mod.rs deleted file mode 100644 index b31fdaa002..0000000000 --- a/frontend/rust-lib/event-integration-test/tests/user/supabase_test/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod auth_test; -mod workspace_test; diff --git a/frontend/rust-lib/event-integration-test/tests/user/supabase_test/workspace_test.rs b/frontend/rust-lib/event-integration-test/tests/user/supabase_test/workspace_test.rs deleted file mode 100644 index 2ccbc9438f..0000000000 --- a/frontend/rust-lib/event-integration-test/tests/user/supabase_test/workspace_test.rs +++ /dev/null @@ -1,43 +0,0 @@ -use std::collections::HashMap; - -use event_integration_test::{event_builder::EventBuilder, EventIntegrationTest}; -use flowy_folder::entities::WorkspaceSettingPB; -use flowy_folder::event_map::FolderEvent::GetCurrentWorkspaceSetting; -use flowy_server::supabase::define::{USER_EMAIL, USER_UUID}; -use flowy_user::entities::{AuthenticatorPB, OauthSignInPB, UserProfilePB}; -use flowy_user::event_map::UserEvent::*; - -use crate::util::*; - -#[tokio::test] -async fn initial_workspace_test() { - if get_supabase_config().is_some() { - let test = EventIntegrationTest::new().await; - let mut map = HashMap::new(); - map.insert(USER_UUID.to_string(), uuid::Uuid::new_v4().to_string()); - map.insert( - USER_EMAIL.to_string(), - format!("{}@gmail.com", uuid::Uuid::new_v4()), - ); - let payload = OauthSignInPB { - map, - authenticator: AuthenticatorPB::Supabase, - }; - - let _ = EventBuilder::new(test.clone()) - .event(OauthSignIn) - .payload(payload) - .async_send() - .await - .parse::(); - - let workspace_settings = EventBuilder::new(test.clone()) - .event(GetCurrentWorkspaceSetting) - .async_send() - .await - .parse::(); - - assert!(workspace_settings.latest_view.is_some()); - dbg!(&workspace_settings); - } -}