Add IO tests for gns tx payloads

next
Sayan Nandan 1 year ago
parent ea20611ebe
commit 9133949beb
No known key found for this signature in database
GPG Key ID: 42EEDF4AE9D96B54

@ -197,6 +197,9 @@ impl DeltaVersion {
fn step(&self) -> Self {
Self(self.0 + 1)
}
pub const fn value_u64(&self) -> u64 {
self.0
}
}
impl DeltaState {

@ -24,6 +24,8 @@
*
*/
use super::txn::TransactionError;
pub type LangResult<T> = Result<T, LangError>;
pub type LexResult<T> = Result<T, LexError>;
pub type DatabaseResult<T> = Result<T, DatabaseError>;
@ -133,4 +135,11 @@ pub enum DatabaseError {
/// field definition violation
DmlConstraintViolationFieldTypedef,
ServerError,
TransactionalError,
}
impl From<TransactionError> for DatabaseError {
fn from(_: TransactionError) -> Self {
Self::TransactionalError
}
}

@ -236,6 +236,9 @@ pub mod enc {
pub fn enc_full_into_buffer<Obj: PersistObject>(buf: &mut VecU8, obj: Obj::InputType) {
Obj::default_full_enc(buf, obj)
}
pub fn enc_full_self<Obj: PersistObject<InputType = Obj>>(obj: Obj) -> Vec<u8> {
enc_full::<Obj>(obj)
}
// dict
pub fn enc_dict_full<PM: PersistMapSpec>(dict: &PM::MapType) -> Vec<u8> {
let mut v = vec![];
@ -253,6 +256,7 @@ pub mod dec {
super::{map, PersistMapSpec, PersistObject},
crate::engine::storage::v1::{rw::BufferedScanner, SDSSResult},
};
// obj
pub fn dec_full<Obj: PersistObject>(data: &[u8]) -> SDSSResult<Obj::OutputType> {
let mut scanner = BufferedScanner::new(data);
dec_full_from_scanner::<Obj>(&mut scanner)
@ -262,6 +266,10 @@ pub mod dec {
) -> SDSSResult<Obj::OutputType> {
Obj::default_full_dec(scanner)
}
pub fn dec_full_self<Obj: PersistObject<OutputType = Obj>>(data: &[u8]) -> SDSSResult<Obj> {
dec_full::<Obj>(data)
}
// dec
pub fn dec_dict_full<PM: PersistMapSpec>(data: &[u8]) -> SDSSResult<PM::MapType> {
let mut scanner = BufferedScanner::new(data);
dec_dict_full_from_scanner::<PM>(&mut scanner)

@ -28,7 +28,7 @@ use {
super::{TransactionError, TransactionResult},
crate::{
engine::{
core::GlobalNS,
core::{space::Space, GlobalNS},
data::uuid::Uuid,
storage::v1::{
inf::{self, PersistObject},
@ -136,10 +136,27 @@ pub struct SpaceIDRef<'a> {
uuid: Uuid,
name: &'a str,
}
impl<'a> SpaceIDRef<'a> {
pub fn new(name: &'a str, space: &Space) -> Self {
Self {
uuid: space.get_uuid(),
name,
}
}
}
#[derive(Debug, PartialEq)]
pub struct SpaceIDRes {
uuid: Uuid,
name: Box<str>,
}
impl SpaceIDRes {
pub fn new(uuid: Uuid, name: Box<str>) -> Self {
Self { uuid, name }
}
}
struct SpaceID<'a>(PhantomData<SpaceIDRef<'a>>);
pub struct SpaceIDMD {
uuid: Uuid,

@ -55,12 +55,45 @@ pub struct ModelIDRef<'a> {
model_uuid: Uuid,
model_version: u64,
}
impl<'a> ModelIDRef<'a> {
pub fn new(
space_id: super::SpaceIDRef<'a>,
model_name: &'a str,
model_uuid: Uuid,
model_version: u64,
) -> Self {
Self {
space_id,
model_name,
model_uuid,
model_version,
}
}
}
#[derive(Debug, PartialEq)]
pub struct ModelIDRes {
space_id: super::SpaceIDRes,
model_name: Box<str>,
model_uuid: Uuid,
model_version: u64,
}
impl ModelIDRes {
pub fn new(
space_id: super::SpaceIDRes,
model_name: Box<str>,
model_uuid: Uuid,
model_version: u64,
) -> Self {
Self {
space_id,
model_name,
model_uuid,
model_version,
}
}
}
pub struct ModelIDMD {
space_id: super::SpaceIDMD,
model_name_l: u64,
@ -169,10 +202,12 @@ impl<'a> CreateModelTxn<'a> {
}
}
#[derive(Debug)]
#[cfg_attr(test, derive(PartialEq))]
pub struct CreateModelTxnRestorePL {
space_id: super::SpaceIDRes,
model_name: Box<str>,
model: Model,
pub(super) space_id: super::SpaceIDRes,
pub(super) model_name: Box<str>,
pub(super) model: Model,
}
pub struct CreateModelTxnMD {
@ -297,9 +332,11 @@ pub struct AlterModelAddTxnMD {
model_id_meta: ModelIDMD,
new_field_c: u64,
}
#[derive(Debug)]
#[cfg_attr(test, derive(PartialEq))]
pub struct AlterModelAddTxnRestorePL {
model_id: ModelIDRes,
new_fields: IndexSTSeqCns<Box<str>, Field>,
pub(super) model_id: ModelIDRes,
pub(super) new_fields: IndexSTSeqCns<Box<str>, Field>,
}
impl<'a> PersistObject for AlterModelAddTxn<'a> {
const METADATA_SIZE: usize = <ModelID as PersistObject>::METADATA_SIZE + sizeof!(u64);
@ -392,9 +429,10 @@ pub struct AlterModelRemoveTxnMD {
model_id_meta: ModelIDMD,
remove_field_c: u64,
}
#[derive(Debug, PartialEq)]
pub struct AlterModelRemoveTxnRestorePL {
model_id: ModelIDRes,
removed_fields: Box<[Box<str>]>,
pub(super) model_id: ModelIDRes,
pub(super) removed_fields: Box<[Box<str>]>,
}
impl<'a> PersistObject for AlterModelRemoveTxn<'a> {
@ -507,9 +545,10 @@ pub struct AlterModelUpdateTxnMD {
model_id_md: ModelIDMD,
updated_field_c: u64,
}
#[derive(Debug, PartialEq)]
pub struct AlterModelUpdateTxnRestorePL {
model_id: ModelIDRes,
updated_fields: IndexST<Box<str>, Field>,
pub(super) model_id: ModelIDRes,
pub(super) updated_fields: IndexST<Box<str>, Field>,
}
impl<'a> PersistObject for AlterModelUpdateTxn<'a> {
@ -602,13 +641,10 @@ impl<'a> DropModelTxn<'a> {
pub struct DropModelTxnMD {
model_id_md: ModelIDMD,
}
pub struct DropModelTxnRestorePL {
model_id: ModelIDRes,
}
impl<'a> PersistObject for DropModelTxn<'a> {
const METADATA_SIZE: usize = <ModelID as PersistObject>::METADATA_SIZE;
type InputType = DropModelTxn<'a>;
type OutputType = DropModelTxnRestorePL;
type OutputType = ModelIDRes;
type Metadata = DropModelTxnMD;
fn pretest_can_dec_object(scanner: &BufferedScanner, md: &Self::Metadata) -> bool {
scanner.has_left(
@ -626,24 +662,26 @@ impl<'a> PersistObject for DropModelTxn<'a> {
<ModelID as PersistObject>::obj_enc(buf, data.model_id);
}
unsafe fn obj_dec(s: &mut BufferedScanner, md: Self::Metadata) -> SDSSResult<Self::OutputType> {
let model_id = <ModelID as PersistObject>::obj_dec(s, md.model_id_md)?;
Ok(DropModelTxnRestorePL { model_id })
<ModelID as PersistObject>::obj_dec(s, md.model_id_md)
}
}
impl<'a> GNSEvent for DropModelTxn<'a> {
const OPC: u16 = 7;
type CommitType = DropModelTxn<'a>;
type RestoreType = DropModelTxnRestorePL;
type RestoreType = ModelIDRes;
fn update_global_state(
DropModelTxnRestorePL { model_id }: Self::RestoreType,
ModelIDRes {
space_id,
model_name,
model_uuid,
model_version: _,
}: Self::RestoreType,
gns: &GlobalNS,
) -> TransactionResult<()> {
with_space(gns, &model_id.space_id, |space| {
with_space(gns, &space_id, |space| {
let mut wgns = space.models().write();
match wgns.st_delete_if(&model_id.model_name, |mdl| {
mdl.get_uuid() == model_id.model_uuid
}) {
match wgns.st_delete_if(&model_name, |mdl| mdl.get_uuid() == model_uuid) {
Some(true) => Ok(()),
Some(false) => return Err(TransactionError::OnRestoreDataConflictMismatch),
None => Err(TransactionError::OnRestoreDataMissing),

@ -48,9 +48,9 @@ use {
#[derive(Clone, Copy)]
/// Transaction commit payload for a `create space ...` query
pub struct CreateSpaceTxn<'a> {
pub(crate) space_meta: &'a DictGeneric,
pub(crate) space_name: &'a str,
pub(crate) space: &'a Space,
pub(super) space_meta: &'a DictGeneric,
pub(super) space_name: &'a str,
pub(super) space: &'a Space,
}
impl<'a> CreateSpaceTxn<'a> {
@ -63,14 +63,16 @@ impl<'a> CreateSpaceTxn<'a> {
}
}
#[derive(Debug)]
#[cfg_attr(test, derive(PartialEq))]
pub struct CreateSpaceTxnRestorePL {
pub(crate) space_name: Box<str>,
pub(crate) space: Space,
pub(super) space_name: Box<str>,
pub(super) space: Space,
}
pub struct CreateSpaceTxnMD {
pub(crate) space_name_l: u64,
pub(crate) space_meta: <obj::SpaceLayoutRef<'static> as PersistObject>::Metadata,
pub(super) space_name_l: u64,
pub(super) space_meta: <obj::SpaceLayoutRef<'static> as PersistObject>::Metadata,
}
impl<'a> PersistObject for CreateSpaceTxn<'a> {
@ -153,9 +155,10 @@ pub struct AlterSpaceTxnMD {
dict_len: u64,
}
#[derive(Debug, PartialEq)]
pub struct AlterSpaceTxnRestorePL {
space_id: super::SpaceIDRes,
space_meta: DictGeneric,
pub(super) space_id: super::SpaceIDRes,
pub(super) space_meta: DictGeneric,
}
impl<'a> PersistObject for AlterSpaceTxn<'a> {

@ -0,0 +1,250 @@
/*
* Created on Thu Aug 24 2023
*
* This file is a part of Skytable
* Skytable (formerly known as TerrabaseDB or Skybase) is a free and open-source
* NoSQL database written by Sayan Nandan ("the Author") with the
* vision to provide flexibility in data modelling without compromising
* on performance, queryability or scalability.
*
* Copyright (c) 2023, Sayan Nandan <ohsayan@outlook.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
use {
super::super::{
model::{self, ModelIDRef, ModelIDRes},
space, SpaceIDRef, SpaceIDRes,
},
crate::engine::{
core::{model::Model, space::Space},
storage::v1::inf::{dec, enc},
},
};
mod space_tests {
use super::{
dec, enc,
space::{
AlterSpaceTxn, AlterSpaceTxnRestorePL, CreateSpaceTxn, CreateSpaceTxnRestorePL,
DropSpaceTxn,
},
Space, SpaceIDRef,
};
#[test]
fn create() {
let orig_space = Space::empty();
let space_r = orig_space.metadata().env().read();
let txn = CreateSpaceTxn::new(&space_r, "myspace", &orig_space);
let encoded = enc::enc_full_self(txn);
let decoded = dec::dec_full::<CreateSpaceTxn>(&encoded).unwrap();
assert_eq!(
CreateSpaceTxnRestorePL {
space_name: "myspace".into(),
space: Space::empty_with_uuid(orig_space.get_uuid())
},
decoded
);
}
#[test]
fn alter() {
let space = Space::empty();
let space_r = space.metadata().env().read();
let txn = AlterSpaceTxn::new(SpaceIDRef::new("myspace", &space), &space_r);
let encoded = enc::enc_full_self(txn);
let decoded = dec::dec_full::<AlterSpaceTxn>(&encoded).unwrap();
assert_eq!(
AlterSpaceTxnRestorePL {
space_id: super::SpaceIDRes::new(space.get_uuid(), "myspace".into()),
space_meta: space_r.clone()
},
decoded
);
}
#[test]
fn drop() {
let space = Space::empty();
let txn = DropSpaceTxn::new(super::SpaceIDRef::new("myspace", &space));
let encoded = enc::enc_full_self(txn);
let decoded = dec::dec_full::<DropSpaceTxn>(&encoded).unwrap();
assert_eq!(
super::SpaceIDRes::new(space.get_uuid(), "myspace".into()),
decoded
);
}
}
mod model_tests {
use {
super::{
model::{
AlterModelAddTxn, AlterModelAddTxnRestorePL, AlterModelRemoveTxn,
AlterModelRemoveTxnRestorePL, AlterModelUpdateTxn, AlterModelUpdateTxnRestorePL,
CreateModelTxn, CreateModelTxnRestorePL, DropModelTxn,
},
Model, Space,
},
crate::engine::{
core::model::{Field, Layer},
data::{tag::TagSelector, uuid::Uuid},
},
};
fn default_space_model() -> (Space, Model) {
let space = Space::empty();
let model = Model::new_restore(
Uuid::new(),
"username".into(),
TagSelector::Str.into_full(),
into_dict!(
"password" => Field::new([Layer::bin()].into(), false),
"profile_pic" => Field::new([Layer::bin()].into(), true),
),
);
(space, model)
}
#[test]
fn create() {
let (space, model) = default_space_model();
let irm = model.intent_read_model();
let txn = CreateModelTxn::new(
super::SpaceIDRef::new("myspace", &space),
"mymodel",
&model,
&irm,
);
let encoded = super::enc::enc_full_self(txn);
core::mem::drop(irm);
let decoded = super::dec::dec_full::<CreateModelTxn>(&encoded).unwrap();
assert_eq!(
CreateModelTxnRestorePL {
space_id: super::SpaceIDRes::new(space.get_uuid(), "myspace".into()),
model_name: "mymodel".into(),
model,
},
decoded
)
}
#[test]
fn alter_add() {
let (space, model) = default_space_model();
let new_fields = into_dict! {
"auth_2fa" => Field::new([Layer::bool()].into(), true),
};
let txn = AlterModelAddTxn::new(
super::ModelIDRef::new(
super::SpaceIDRef::new("myspace", &space),
"mymodel",
model.get_uuid(),
model.delta_state().current_version().value_u64(),
),
&new_fields,
);
let encoded = super::enc::enc_full_self(txn);
let decoded = super::dec::dec_full::<AlterModelAddTxn>(&encoded).unwrap();
assert_eq!(
AlterModelAddTxnRestorePL {
model_id: super::ModelIDRes::new(
super::SpaceIDRes::new(space.get_uuid(), "myspace".into()),
"mymodel".into(),
model.get_uuid(),
model.delta_state().current_version().value_u64()
),
new_fields
},
decoded
);
}
#[test]
fn alter_remove() {
let (space, model) = default_space_model();
let removed_fields = ["profile_pic".into()];
let txn = AlterModelRemoveTxn::new(
super::ModelIDRef::new(
super::SpaceIDRef::new("myspace", &space),
"mymodel",
model.get_uuid(),
model.delta_state().current_version().value_u64(),
),
&removed_fields,
);
let encoded = super::enc::enc_full_self(txn);
let decoded = super::dec::dec_full::<AlterModelRemoveTxn>(&encoded).unwrap();
assert_eq!(
AlterModelRemoveTxnRestorePL {
model_id: super::ModelIDRes::new(
super::SpaceIDRes::new(space.get_uuid(), "myspace".into()),
"mymodel".into(),
model.get_uuid(),
model.delta_state().current_version().value_u64()
),
removed_fields: ["profile_pic".into()].into()
},
decoded
);
}
#[test]
fn alter_update() {
let (space, model) = default_space_model();
let updated_fields = into_dict! {
// people of your social app will hate this, but hehe
"profile_pic" => Field::new([Layer::bin()].into(), false)
};
let txn = AlterModelUpdateTxn::new(
super::ModelIDRef::new(
super::SpaceIDRef::new("myspace", &space),
"mymodel".into(),
model.get_uuid(),
model.delta_state().current_version().value_u64(),
),
&updated_fields,
);
let encoded = super::enc::enc_full_self(txn);
let decoded = super::dec::dec_full::<AlterModelUpdateTxn>(&encoded).unwrap();
assert_eq!(
AlterModelUpdateTxnRestorePL {
model_id: super::ModelIDRes::new(
super::SpaceIDRes::new(space.get_uuid(), "myspace".into()),
"mymodel".into(),
model.get_uuid(),
model.delta_state().current_version().value_u64()
),
updated_fields
},
decoded
);
}
#[test]
fn drop() {
let (space, model) = default_space_model();
let txn = DropModelTxn::new(super::ModelIDRef::new(
super::SpaceIDRef::new("myspace", &space),
"mymodel",
model.get_uuid(),
model.delta_state().current_version().value_u64(),
));
let encoded = super::enc::enc_full_self(txn);
let decoded = super::dec::dec_full::<DropModelTxn>(&encoded).unwrap();
assert_eq!(
super::ModelIDRes::new(
super::SpaceIDRes::new(space.get_uuid(), "myspace".into()),
"mymodel".into(),
model.get_uuid(),
model.delta_state().current_version().value_u64()
),
decoded
);
}
}
Loading…
Cancel
Save