mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
Feat/restore revision (#1549)
* chore: write snapshot * chore: add tests * chore: sync close * chore: restore from snapshot * chore: delete invalid revisions after restored from snapshot * chore: create default view if it fail to deserialize view's revisions when there is no snapshot * chore: auto generate snapshot Co-authored-by: nathan <nathan@appflowy.io>
This commit is contained in:
@ -60,7 +60,7 @@ impl GridFieldTest {
|
||||
FieldScript::CreateField { params } => {
|
||||
self.field_count += 1;
|
||||
self.editor
|
||||
.create_new_field_rev(¶ms.field_type, params.type_option_data)
|
||||
.create_new_field_rev_with_type_option(¶ms.field_type, params.type_option_data)
|
||||
.await
|
||||
.unwrap();
|
||||
self.field_revs = self.editor.get_field_revs(None).await.unwrap();
|
||||
|
@ -462,7 +462,7 @@ async fn group_insert_single_select_option_test() {
|
||||
AssertGroupCount(5),
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
let new_group = test.group_at_index(1).await;
|
||||
let new_group = test.group_at_index(4).await;
|
||||
assert_eq!(new_group.desc, new_option_name);
|
||||
}
|
||||
|
||||
|
@ -4,3 +4,4 @@ mod field_test;
|
||||
mod filter_test;
|
||||
mod grid_editor;
|
||||
mod group_test;
|
||||
mod snapshot_test;
|
||||
|
@ -0,0 +1,2 @@
|
||||
mod script;
|
||||
mod test;
|
105
frontend/rust-lib/flowy-grid/tests/grid/snapshot_test/script.rs
Normal file
105
frontend/rust-lib/flowy-grid/tests/grid/snapshot_test/script.rs
Normal file
@ -0,0 +1,105 @@
|
||||
use crate::grid::grid_editor::GridEditorTest;
|
||||
|
||||
use flowy_http_model::revision::Revision;
|
||||
use flowy_revision::{RevisionSnapshot, REVISION_WRITE_INTERVAL_IN_MILLIS};
|
||||
use flowy_sync::client_grid::{GridOperations, GridRevisionPad};
|
||||
use grid_rev_model::FieldRevision;
|
||||
use std::time::Duration;
|
||||
use tokio::time::sleep;
|
||||
|
||||
pub enum SnapshotScript {
|
||||
WriteSnapshot,
|
||||
#[allow(dead_code)]
|
||||
AssertSnapshot {
|
||||
rev_id: i64,
|
||||
expected: Option<RevisionSnapshot>,
|
||||
},
|
||||
AssertSnapshotContent {
|
||||
snapshot: RevisionSnapshot,
|
||||
expected: String,
|
||||
},
|
||||
CreateField {
|
||||
field_rev: FieldRevision,
|
||||
},
|
||||
DeleteField {
|
||||
field_rev: FieldRevision,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct GridSnapshotTest {
|
||||
inner: GridEditorTest,
|
||||
pub current_snapshot: Option<RevisionSnapshot>,
|
||||
pub current_revision: Option<Revision>,
|
||||
}
|
||||
|
||||
impl GridSnapshotTest {
|
||||
pub async fn new() -> Self {
|
||||
let editor_test = GridEditorTest::new_table().await;
|
||||
Self {
|
||||
inner: editor_test,
|
||||
current_snapshot: None,
|
||||
current_revision: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn grid_id(&self) -> String {
|
||||
self.grid_id.clone()
|
||||
}
|
||||
|
||||
pub async fn grid_pad(&self) -> GridRevisionPad {
|
||||
let pad = self.editor.grid_pad();
|
||||
let pad = (*pad.read().await).clone();
|
||||
pad
|
||||
}
|
||||
|
||||
pub async fn run_scripts(&mut self, scripts: Vec<SnapshotScript>) {
|
||||
for script in scripts {
|
||||
self.run_script(script).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_latest_snapshot(&self) -> Option<RevisionSnapshot> {
|
||||
self.editor.rev_manager().read_snapshot(None).await.unwrap()
|
||||
}
|
||||
|
||||
pub async fn run_script(&mut self, script: SnapshotScript) {
|
||||
let rev_manager = self.editor.rev_manager();
|
||||
match script {
|
||||
SnapshotScript::WriteSnapshot => {
|
||||
sleep(Duration::from_millis(2 * REVISION_WRITE_INTERVAL_IN_MILLIS)).await;
|
||||
rev_manager.generate_snapshot().await;
|
||||
self.current_snapshot = rev_manager.read_snapshot(None).await.unwrap();
|
||||
}
|
||||
SnapshotScript::AssertSnapshot { rev_id, expected } => {
|
||||
let snapshot = rev_manager.read_snapshot(Some(rev_id)).await.unwrap();
|
||||
assert_eq!(snapshot, expected);
|
||||
}
|
||||
SnapshotScript::AssertSnapshotContent { snapshot, expected } => {
|
||||
let operations = GridOperations::from_bytes(snapshot.data).unwrap();
|
||||
let pad = GridRevisionPad::from_operations(operations).unwrap();
|
||||
assert_eq!(pad.json_str().unwrap(), expected);
|
||||
}
|
||||
SnapshotScript::CreateField { field_rev } => {
|
||||
self.editor.create_new_field_rev(field_rev).await.unwrap();
|
||||
let current_rev_id = rev_manager.rev_id();
|
||||
self.current_revision = rev_manager.get_revision(current_rev_id).await;
|
||||
}
|
||||
SnapshotScript::DeleteField { field_rev } => {
|
||||
self.editor.delete_field(&field_rev.id).await.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl std::ops::Deref for GridSnapshotTest {
|
||||
type Target = GridEditorTest;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for GridSnapshotTest {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
use crate::grid::field_test::util::create_text_field;
|
||||
use crate::grid::snapshot_test::script::{GridSnapshotTest, SnapshotScript::*};
|
||||
|
||||
#[tokio::test]
|
||||
async fn snapshot_create_test() {
|
||||
let mut test = GridSnapshotTest::new().await;
|
||||
let (_, field_rev) = create_text_field(&test.grid_id());
|
||||
let scripts = vec![CreateField { field_rev }, WriteSnapshot];
|
||||
test.run_scripts(scripts).await;
|
||||
|
||||
let snapshot = test.current_snapshot.clone().unwrap();
|
||||
let content = test.grid_pad().await.json_str().unwrap();
|
||||
test.run_scripts(vec![AssertSnapshotContent {
|
||||
snapshot,
|
||||
expected: content,
|
||||
}])
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn snapshot_multi_version_test() {
|
||||
let mut test = GridSnapshotTest::new().await;
|
||||
let original_content = test.grid_pad().await.json_str().unwrap();
|
||||
|
||||
// Create a field
|
||||
let (_, field_rev) = create_text_field(&test.grid_id());
|
||||
let scripts = vec![
|
||||
CreateField {
|
||||
field_rev: field_rev.clone(),
|
||||
},
|
||||
WriteSnapshot,
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
|
||||
// Delete a field
|
||||
let scripts = vec![DeleteField { field_rev }, WriteSnapshot];
|
||||
test.run_scripts(scripts).await;
|
||||
|
||||
// The latest snapshot will be the same as the original content.
|
||||
test.run_scripts(vec![AssertSnapshotContent {
|
||||
snapshot: test.get_latest_snapshot().await.unwrap(),
|
||||
expected: original_content,
|
||||
}])
|
||||
.await;
|
||||
}
|
Reference in New Issue
Block a user