-
Notifications
You must be signed in to change notification settings - Fork 117
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: Update resolution atomicity and stream operations. (#1390)
- Loading branch information
Showing
15 changed files
with
872 additions
and
668 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
256 changes: 256 additions & 0 deletions
256
dozer-cache/src/cache/lmdb/cache/main_environment/conflict_resolution_tests.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,256 @@ | ||
use crate::cache::index; | ||
use crate::cache::lmdb::cache::MainEnvironment; | ||
use crate::cache::test_utils::schema_multi_indices; | ||
use crate::errors::CacheError; | ||
use dozer_types::models::api_endpoint::{ | ||
ConflictResolution, OnDeleteResolutionTypes, OnInsertResolutionTypes, OnUpdateResolutionTypes, | ||
}; | ||
use dozer_types::types::{Field, Record, Schema}; | ||
|
||
use super::RwMainEnvironment; | ||
|
||
fn init_env(conflict_resolution: ConflictResolution) -> (RwMainEnvironment, Schema) { | ||
let schema = schema_multi_indices(); | ||
let main_env = | ||
RwMainEnvironment::new(Some(&schema), &Default::default(), conflict_resolution).unwrap(); | ||
(main_env, schema.0) | ||
} | ||
|
||
#[test] | ||
fn ignore_insert_error_when_type_nothing() { | ||
let (mut env, schema) = init_env(ConflictResolution { | ||
on_insert: OnInsertResolutionTypes::Nothing as i32, | ||
on_update: OnUpdateResolutionTypes::default() as i32, | ||
on_delete: OnDeleteResolutionTypes::default() as i32, | ||
}); | ||
|
||
let initial_values = vec![Field::Int(1), Field::String("Film name old".to_string())]; | ||
let record = Record { | ||
schema_id: schema.identifier, | ||
values: initial_values.clone(), | ||
version: None, | ||
}; | ||
env.insert(&record).unwrap(); | ||
env.commit().unwrap(); | ||
|
||
let key = index::get_primary_key(&schema.primary_index, &initial_values); | ||
let record = env.get(&key).unwrap().record; | ||
|
||
assert_eq!(initial_values, record.values); | ||
assert_eq!(Some(1), record.version); | ||
|
||
env.insert(&record).unwrap(); | ||
|
||
let record = env.get(&key).unwrap().record; | ||
|
||
// version should remain unchanged, because insert should be ignored | ||
assert_eq!(initial_values, record.values); | ||
assert_eq!(Some(1), record.version); | ||
} | ||
|
||
#[test] | ||
fn update_after_insert_error_when_type_update() { | ||
let (mut env, schema) = init_env(ConflictResolution { | ||
on_insert: OnInsertResolutionTypes::Update as i32, | ||
on_update: OnUpdateResolutionTypes::default() as i32, | ||
on_delete: OnDeleteResolutionTypes::default() as i32, | ||
}); | ||
|
||
let initial_values = vec![Field::Int(1), Field::String("Film name old".to_string())]; | ||
let record = Record { | ||
schema_id: schema.identifier, | ||
values: initial_values.clone(), | ||
version: None, | ||
}; | ||
env.insert(&record).unwrap(); | ||
env.commit().unwrap(); | ||
|
||
let key = index::get_primary_key(&schema.primary_index, &initial_values); | ||
let record = env.get(&key).unwrap().record; | ||
|
||
assert_eq!(initial_values, record.values); | ||
assert_eq!(Some(1), record.version); | ||
|
||
let second_insert_values = vec![ | ||
Field::Int(1), | ||
Field::String("Second insert name".to_string()), | ||
]; | ||
let second_record = Record { | ||
schema_id: schema.identifier, | ||
values: second_insert_values.clone(), | ||
version: None, | ||
}; | ||
|
||
env.insert(&second_record).unwrap(); | ||
env.commit().unwrap(); | ||
|
||
let key = index::get_primary_key(&schema.primary_index, &initial_values); | ||
let record = env.get(&key).unwrap().record; | ||
|
||
// version should increase, because record should be updated | ||
assert_eq!(second_insert_values, record.values); | ||
assert_eq!(Some(2), record.version); | ||
|
||
// Check cache size. It should have only one record | ||
let current_count = env.count().unwrap(); | ||
assert_eq!(current_count, 1_usize); | ||
} | ||
|
||
#[test] | ||
fn return_insert_error_when_type_panic() { | ||
let (mut env, schema) = init_env(ConflictResolution { | ||
on_insert: OnInsertResolutionTypes::Panic as i32, | ||
on_update: OnUpdateResolutionTypes::default() as i32, | ||
on_delete: OnDeleteResolutionTypes::default() as i32, | ||
}); | ||
|
||
let initial_values = vec![Field::Int(1), Field::String("Film name old".to_string())]; | ||
let record = Record { | ||
schema_id: schema.identifier, | ||
values: initial_values.clone(), | ||
version: None, | ||
}; | ||
env.insert(&record).unwrap(); | ||
env.commit().unwrap(); | ||
|
||
let key = index::get_primary_key(&schema.primary_index, &initial_values); | ||
let record = env.get(&key).unwrap().record; | ||
|
||
assert_eq!(initial_values, record.values); | ||
assert_eq!(Some(1), record.version); | ||
|
||
// Try insert same data again | ||
let result = env.insert(&record); | ||
assert!(matches!(result, Err(CacheError::PrimaryKeyExists))); | ||
} | ||
|
||
#[test] | ||
fn ignore_update_error_when_type_nothing() { | ||
let (mut env, schema) = init_env(ConflictResolution { | ||
on_insert: OnInsertResolutionTypes::default() as i32, | ||
on_update: OnUpdateResolutionTypes::Nothing as i32, | ||
on_delete: OnDeleteResolutionTypes::default() as i32, | ||
}); | ||
|
||
let initial_values = vec![Field::Int(1), Field::Null]; | ||
let update_values = vec![ | ||
Field::Int(1), | ||
Field::String("Film name updated".to_string()), | ||
]; | ||
|
||
let update_record = Record { | ||
schema_id: schema.identifier, | ||
values: update_values, | ||
version: None, | ||
}; | ||
env.update( | ||
&index::get_primary_key(&schema.primary_index, &initial_values), | ||
&update_record, | ||
) | ||
.unwrap(); | ||
|
||
let key = index::get_primary_key(&schema.primary_index, &initial_values); | ||
let record = env.get(&key); | ||
|
||
assert!(matches!(record, Err(CacheError::PrimaryKeyNotFound))); | ||
} | ||
|
||
#[test] | ||
fn update_after_update_error_when_type_upsert() { | ||
let (mut env, schema) = init_env(ConflictResolution { | ||
on_insert: OnInsertResolutionTypes::default() as i32, | ||
on_update: OnUpdateResolutionTypes::Upsert as i32, | ||
on_delete: OnDeleteResolutionTypes::default() as i32, | ||
}); | ||
|
||
let initial_values = vec![Field::Int(1), Field::Null]; | ||
let update_values = vec![ | ||
Field::Int(1), | ||
Field::String("Film name updated".to_string()), | ||
]; | ||
|
||
let update_record = Record { | ||
schema_id: schema.identifier, | ||
values: update_values.clone(), | ||
version: None, | ||
}; | ||
env.update( | ||
&index::get_primary_key(&schema.primary_index, &initial_values), | ||
&update_record, | ||
) | ||
.unwrap(); | ||
env.commit().unwrap(); | ||
|
||
let key = index::get_primary_key(&schema.primary_index, &initial_values); | ||
let record = env.get(&key).unwrap().record; | ||
|
||
assert_eq!(update_values, record.values); | ||
assert_eq!(Some(1), record.version); | ||
} | ||
|
||
#[test] | ||
fn return_update_error_when_type_panic() { | ||
let (mut env, schema) = init_env(ConflictResolution { | ||
on_insert: OnInsertResolutionTypes::default() as i32, | ||
on_update: OnUpdateResolutionTypes::Panic as i32, | ||
on_delete: OnInsertResolutionTypes::default() as i32, | ||
}); | ||
|
||
let initial_values = vec![Field::Int(1), Field::Null]; | ||
let update_values = vec![ | ||
Field::Int(1), | ||
Field::String("Film name updated".to_string()), | ||
]; | ||
|
||
let update_record = Record { | ||
schema_id: schema.identifier, | ||
values: update_values.clone(), | ||
version: None, | ||
}; | ||
|
||
let result = env.update( | ||
&index::get_primary_key(&schema.primary_index, &initial_values), | ||
&update_record, | ||
); | ||
|
||
assert!(matches!(result, Err(CacheError::PrimaryKeyNotFound))); | ||
} | ||
|
||
#[test] | ||
fn ignore_delete_error_when_type_nothing() { | ||
let (mut env, schema) = init_env(ConflictResolution { | ||
on_insert: OnInsertResolutionTypes::default() as i32, | ||
on_update: OnUpdateResolutionTypes::default() as i32, | ||
on_delete: OnUpdateResolutionTypes::Nothing as i32, | ||
}); | ||
|
||
let initial_values = vec![Field::Int(1), Field::Null]; | ||
|
||
// Check is cache empty | ||
let current_count = env.count().unwrap(); | ||
assert_eq!(current_count, 0_usize); | ||
|
||
// Trying delete not existing record should be ignored | ||
let result = env.delete(&index::get_primary_key( | ||
&schema.primary_index, | ||
&initial_values, | ||
)); | ||
assert!(result.is_ok()); | ||
} | ||
|
||
#[test] | ||
fn return_delete_error_when_type_panic() { | ||
let (mut env, schema) = init_env(ConflictResolution { | ||
on_insert: OnInsertResolutionTypes::default() as i32, | ||
on_update: OnUpdateResolutionTypes::default() as i32, | ||
on_delete: OnDeleteResolutionTypes::Panic as i32, | ||
}); | ||
|
||
let initial_values = vec![Field::Int(1), Field::Null]; | ||
|
||
let result = env.delete(&index::get_primary_key( | ||
&schema.primary_index, | ||
&initial_values, | ||
)); | ||
assert!(matches!(result, Err(CacheError::PrimaryKeyNotFound))); | ||
} |
Oops, something went wrong.