From 72b830f408ccfec391600d5839a929384a6e0f60 Mon Sep 17 00:00:00 2001 From: Benno Zeeman Date: Thu, 23 Jan 2025 14:49:25 +0100 Subject: [PATCH 1/5] feat: add version field to archive and metadata --- .../high_level/files/archive_private.rs | 51 +++++++++++++++---- .../client/high_level/files/archive_public.rs | 40 +++++++++++---- .../src/client/high_level/files/fs_public.rs | 2 + autonomi/src/client/high_level/files/mod.rs | 45 ++++++++++++++++ 4 files changed, 118 insertions(+), 20 deletions(-) diff --git a/autonomi/src/client/high_level/files/archive_private.rs b/autonomi/src/client/high_level/files/archive_private.rs index 29b3b0ab83..c8279532c4 100644 --- a/autonomi/src/client/high_level/files/archive_private.rs +++ b/autonomi/src/client/high_level/files/archive_private.rs @@ -23,7 +23,7 @@ use crate::{ use bytes::Bytes; use serde::{Deserialize, Serialize}; -use super::Metadata; +use super::{Metadata, MetadataVersioned}; /// Private archive data map, allowing access to the [`PrivateArchive`] data. pub type PrivateArchiveAccess = DataMapChunk; @@ -33,7 +33,17 @@ pub type PrivateArchiveAccess = DataMapChunk; /// The data maps are stored within this structure instead of uploading them to the network, keeping the data private. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)] pub struct PrivateArchive { - map: BTreeMap, + map: BTreeMap, +} + +/// This type essentially adds a `version` field to the serialized `PrivateArchive` data. +/// E.g. in JSON format: `{ "version": 0, "map": }` +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[non_exhaustive] +#[serde(tag = "version")] +pub enum PrivateArchiveVersioned { + #[serde(rename = "0")] + V0(PrivateArchive), } impl PrivateArchive { @@ -65,7 +75,8 @@ impl PrivateArchive { /// Add a file to a local archive /// Note that this does not upload the archive to the network pub fn add_file(&mut self, path: PathBuf, data_map: DataMapChunk, meta: Metadata) { - self.map.insert(path.clone(), (data_map, meta)); + self.map + .insert(path.clone(), (data_map, MetadataVersioned::V0(meta))); debug!("Added a new file to the archive, path: {:?}", path); } @@ -73,7 +84,7 @@ impl PrivateArchive { pub fn files(&self) -> Vec<(PathBuf, Metadata)> { self.map .iter() - .map(|(path, (_, meta))| (path.clone(), meta.clone())) + .map(|(path, (_, meta))| (path.clone(), meta.clone().into())) .collect() } @@ -89,26 +100,35 @@ impl PrivateArchive { /// /// Returns an iterator over ([`PathBuf`], [`DataMapChunk`], [`Metadata`]) pub fn iter(&self) -> impl Iterator { - self.map - .iter() - .map(|(path, (data_map, meta))| (path, data_map, meta)) + self.map.iter().map(|(path, (data_map, meta))| { + ( + path, + data_map, + match meta { + MetadataVersioned::V0(meta) => meta, + }, + ) + }) } /// Get the underlying map - pub fn map(&self) -> &BTreeMap { + pub fn map(&self) -> &BTreeMap { &self.map } /// Deserialize from bytes. pub fn from_bytes(data: Bytes) -> Result { - let root: PrivateArchive = rmp_serde::from_slice(&data[..])?; + let root: PrivateArchiveVersioned = rmp_serde::from_slice(&data[..])?; + // Currently we have only `V0`. If we add `V1`, then we need an upgrade/migration path here. + let PrivateArchiveVersioned::V0(root) = root; Ok(root) } /// Serialize to bytes. pub fn to_bytes(&self) -> Result { - let root_serialized = rmp_serde::to_vec(&self)?; + let versioned = PrivateArchiveVersioned::V0(self.clone()); + let root_serialized = rmp_serde::to_vec(&versioned)?; let root_serialized = Bytes::from(root_serialized); Ok(root_serialized) @@ -146,3 +166,14 @@ impl Client { result } } + +#[cfg(test)] +mod test { + #[test] + fn backwards_compatibility() { + let archive = super::PrivateArchive::new(); + let bytes = archive.to_bytes().unwrap(); + let archive2 = super::PrivateArchive::from_bytes(bytes).unwrap(); + assert_eq!(archive, archive2); + } +} diff --git a/autonomi/src/client/high_level/files/archive_public.rs b/autonomi/src/client/high_level/files/archive_public.rs index fc49789c3b..2b93549cb6 100644 --- a/autonomi/src/client/high_level/files/archive_public.rs +++ b/autonomi/src/client/high_level/files/archive_public.rs @@ -27,7 +27,7 @@ use crate::{ Client, }; -use super::Metadata; +use super::{Metadata, MetadataVersioned}; /// The address of a public archive on the network. Points to an [`PublicArchive`]. pub type ArchiveAddr = XorName; @@ -36,7 +36,17 @@ pub type ArchiveAddr = XorName; /// to the network, of which the addresses are stored in this archive. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)] pub struct PublicArchive { - map: BTreeMap, + map: BTreeMap, +} + +/// This type essentially adds a `version` field to the serialized `PublicArchive` data. +/// E.g. in JSON format: `{ "version": 0, "map": }` +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[non_exhaustive] +#[serde(tag = "version")] +pub enum PublicArchiveVersioned { + #[serde(rename = "0")] + V0(PublicArchive), } impl PublicArchive { @@ -68,7 +78,8 @@ impl PublicArchive { /// Add a file to a local archive /// Note that this does not upload the archive to the network pub fn add_file(&mut self, path: PathBuf, data_addr: DataAddr, meta: Metadata) { - self.map.insert(path.clone(), (data_addr, meta)); + self.map + .insert(path.clone(), (data_addr, MetadataVersioned::V0(meta))); debug!("Added a new file to the archive, path: {:?}", path); } @@ -76,7 +87,7 @@ impl PublicArchive { pub fn files(&self) -> Vec<(PathBuf, Metadata)> { self.map .iter() - .map(|(path, (_, meta))| (path.clone(), meta.clone())) + .map(|(path, (_, meta))| (path.clone(), meta.clone().into())) .collect() } @@ -88,26 +99,35 @@ impl PublicArchive { /// Iterate over the archive items /// Returns an iterator over (PathBuf, DataAddr, Metadata) pub fn iter(&self) -> impl Iterator { - self.map - .iter() - .map(|(path, (addr, meta))| (path, addr, meta)) + self.map.iter().map(|(path, (addr, meta))| { + ( + path, + addr, + match meta { + MetadataVersioned::V0(meta) => meta, + }, + ) + }) } /// Get the underlying map - pub fn map(&self) -> &BTreeMap { + pub fn map(&self) -> &BTreeMap { &self.map } /// Deserialize from bytes. pub fn from_bytes(data: Bytes) -> Result { - let root: PublicArchive = rmp_serde::from_slice(&data[..])?; + let root: PublicArchiveVersioned = rmp_serde::from_slice(&data[..])?; + // Currently we have only `V0`. If we add `V1`, then we need an upgrade/migration path here. + let PublicArchiveVersioned::V0(root) = root; Ok(root) } /// Serialize to bytes. pub fn to_bytes(&self) -> Result { - let root_serialized = rmp_serde::to_vec(&self)?; + let versioned = PublicArchiveVersioned::V0(self.clone()); + let root_serialized = rmp_serde::to_vec(&versioned)?; let root_serialized = Bytes::from(root_serialized); Ok(root_serialized) diff --git a/autonomi/src/client/high_level/files/fs_public.rs b/autonomi/src/client/high_level/files/fs_public.rs index 77cb07506f..48578903db 100644 --- a/autonomi/src/client/high_level/files/fs_public.rs +++ b/autonomi/src/client/high_level/files/fs_public.rs @@ -197,6 +197,7 @@ pub(crate) fn metadata_from_entry(entry: &walkdir::DirEntry) -> Metadata { created: 0, modified: 0, size: 0, + extra: None, }; } }; @@ -226,5 +227,6 @@ pub(crate) fn metadata_from_entry(entry: &walkdir::DirEntry) -> Metadata { created, modified, size: fs_metadata.len(), + extra: None, } } diff --git a/autonomi/src/client/high_level/files/mod.rs b/autonomi/src/client/high_level/files/mod.rs index 0b0d1b82a1..088b656ac4 100644 --- a/autonomi/src/client/high_level/files/mod.rs +++ b/autonomi/src/client/high_level/files/mod.rs @@ -39,6 +39,50 @@ pub struct Metadata { pub modified: u64, /// File size in bytes pub size: u64, + + /// Optional extra metadata with undefined structure, e.g. JSON. + pub extra: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[non_exhaustive] +#[serde(tag = "version")] +pub enum MetadataVersioned { + #[serde(rename = "0")] + V0(Metadata), +} + +// Allows us to do access currently only possible `Metadata` struct (V0) conveniently: +// ```rust +// let metadata = MetadataVersioned::V0(Metadata::new_with_size(123)); +// let size = metadata.size; // Access the only possible (currently) `Metadata` (V0) struct +// ``` +impl std::ops::Deref for MetadataVersioned { + type Target = Metadata; + + fn deref(&self) -> &Self::Target { + let MetadataVersioned::V0(v0) = &self; + v0 + } +} +impl std::ops::DerefMut for MetadataVersioned { + fn deref_mut(&mut self) -> &mut Self::Target { + let MetadataVersioned::V0(v0) = self; + v0 + } +} + +impl From for MetadataVersioned { + fn from(value: Metadata) -> Self { + MetadataVersioned::V0(value) + } +} +// Again for convenience. When we add a `V1` we could implement an migration/upgrade path here: +// E.g. we could upgrade `V0` to `V1`, returning our latest/current `V1`. +impl From for Metadata { + fn from(MetadataVersioned::V0(value): MetadataVersioned) -> Self { + value + } } impl Metadata { @@ -53,6 +97,7 @@ impl Metadata { created: now, modified: now, size, + extra: None, } } } From 93fba58cda5d4aa2b60aaa47b741becd0d823ba8 Mon Sep 17 00:00:00 2001 From: Benno Zeeman Date: Tue, 28 Jan 2025 12:14:46 +0100 Subject: [PATCH 2/5] refactor: introduce backwards comp test --- .../high_level/files/archive_private.rs | 6 +- .../client/high_level/files/archive_public.rs | 56 +++++++++++++++++-- autonomi/src/client/high_level/files/mod.rs | 2 +- 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/autonomi/src/client/high_level/files/archive_private.rs b/autonomi/src/client/high_level/files/archive_private.rs index c8279532c4..49994f3392 100644 --- a/autonomi/src/client/high_level/files/archive_private.rs +++ b/autonomi/src/client/high_level/files/archive_private.rs @@ -36,13 +36,11 @@ pub struct PrivateArchive { map: BTreeMap, } -/// This type essentially adds a `version` field to the serialized `PrivateArchive` data. -/// E.g. in JSON format: `{ "version": 0, "map": }` +/// This type essentially wraps archive in version marker. E.g. in JSON format: +/// `{ "V0": { "map": } }` #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[non_exhaustive] -#[serde(tag = "version")] pub enum PrivateArchiveVersioned { - #[serde(rename = "0")] V0(PrivateArchive), } diff --git a/autonomi/src/client/high_level/files/archive_public.rs b/autonomi/src/client/high_level/files/archive_public.rs index 2b93549cb6..eb5bb5930f 100644 --- a/autonomi/src/client/high_level/files/archive_public.rs +++ b/autonomi/src/client/high_level/files/archive_public.rs @@ -39,13 +39,11 @@ pub struct PublicArchive { map: BTreeMap, } -/// This type essentially adds a `version` field to the serialized `PublicArchive` data. -/// E.g. in JSON format: `{ "version": 0, "map": }` +/// This type essentially wraps archive in version marker. E.g. in JSON format: +/// `{ "V0": { "map": } }` #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[non_exhaustive] -#[serde(tag = "version")] pub enum PublicArchiveVersioned { - #[serde(rename = "0")] V0(PublicArchive), } @@ -202,3 +200,53 @@ impl Client { result } } + +#[cfg(test)] +mod test { + use std::str::FromStr; + + use super::*; + + #[test] + fn compatibility() { + // In the future we'll have an extra variant. + #[derive(Serialize, Deserialize)] + #[non_exhaustive] + pub enum FuturePublicArchiveVersioned { + V0(PublicArchive), + V1(PublicArchive), + #[serde(other)] + Unsupported, + } + + let mut arch = PublicArchive::new(); + arch.add_file( + PathBuf::from_str("hello_world").unwrap(), + DataAddr::random(&mut rand::thread_rng()), + Metadata::new_with_size(1), + ); + let arch_serialized = arch.to_bytes().unwrap(); + + // Create archive, forward compatible (still the same V0 version). + let future_arch = FuturePublicArchiveVersioned::V0(arch.clone()); + let future_arch_serialized = rmp_serde::to_vec(&future_arch).unwrap(); + + // Let's see if we can deserialize a (forward compatible) archive arriving to us from the future + let _ = PublicArchive::from_bytes(Bytes::from(future_arch_serialized)).unwrap(); + + // Let's see if we can deserialize an old archive from the future + let _: FuturePublicArchiveVersioned = rmp_serde::from_slice(&arch_serialized[..]).unwrap(); + + // Now we break forward compatibility by introducing a new version not supported by the old code. + let future_arch = FuturePublicArchiveVersioned::V1(arch.clone()); + let future_arch_serialized = rmp_serde::to_vec(&future_arch).unwrap(); + // The old archive will not be able to decode this. + assert!(PublicArchive::from_bytes(Bytes::from(future_arch_serialized)).is_err()); + + // Now we prove backwards compatibility. Our old V0 archive will still be decoded by our new archive wrapper as V0. + let versioned_arch = PublicArchiveVersioned::V0(arch.clone()); // 'Old' archive wrapper + let versioned_arch_serialized = rmp_serde::to_vec(&versioned_arch).unwrap(); + let _: FuturePublicArchiveVersioned = // Into 'new' wrapper + rmp_serde::from_slice(&versioned_arch_serialized[..]).unwrap(); + } +} diff --git a/autonomi/src/client/high_level/files/mod.rs b/autonomi/src/client/high_level/files/mod.rs index 088b656ac4..5c518faaf8 100644 --- a/autonomi/src/client/high_level/files/mod.rs +++ b/autonomi/src/client/high_level/files/mod.rs @@ -52,7 +52,7 @@ pub enum MetadataVersioned { V0(Metadata), } -// Allows us to do access currently only possible `Metadata` struct (V0) conveniently: +// Allows us to access currently only possible `Metadata` struct (V0) conveniently: // ```rust // let metadata = MetadataVersioned::V0(Metadata::new_with_size(123)); // let size = metadata.size; // Access the only possible (currently) `Metadata` (V0) struct From 02ef9434658a2dab6af17c2b8c7adbefaaa1acfd Mon Sep 17 00:00:00 2001 From: Benno Zeeman Date: Thu, 30 Jan 2025 08:57:44 +0100 Subject: [PATCH 3/5] feat: implement Metadata to Mick's model --- .../high_level/files/archive_private.rs | 25 ++++------- .../client/high_level/files/archive_public.rs | 31 ++++++-------- autonomi/src/client/high_level/files/mod.rs | 41 ------------------- 3 files changed, 21 insertions(+), 76 deletions(-) diff --git a/autonomi/src/client/high_level/files/archive_private.rs b/autonomi/src/client/high_level/files/archive_private.rs index 49994f3392..8e3f8599f9 100644 --- a/autonomi/src/client/high_level/files/archive_private.rs +++ b/autonomi/src/client/high_level/files/archive_private.rs @@ -23,7 +23,7 @@ use crate::{ use bytes::Bytes; use serde::{Deserialize, Serialize}; -use super::{Metadata, MetadataVersioned}; +use super::Metadata; /// Private archive data map, allowing access to the [`PrivateArchive`] data. pub type PrivateArchiveAccess = DataMapChunk; @@ -33,7 +33,7 @@ pub type PrivateArchiveAccess = DataMapChunk; /// The data maps are stored within this structure instead of uploading them to the network, keeping the data private. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)] pub struct PrivateArchive { - map: BTreeMap, + map: BTreeMap, } /// This type essentially wraps archive in version marker. E.g. in JSON format: @@ -73,8 +73,7 @@ impl PrivateArchive { /// Add a file to a local archive /// Note that this does not upload the archive to the network pub fn add_file(&mut self, path: PathBuf, data_map: DataMapChunk, meta: Metadata) { - self.map - .insert(path.clone(), (data_map, MetadataVersioned::V0(meta))); + self.map.insert(path.clone(), (data_map, meta)); debug!("Added a new file to the archive, path: {:?}", path); } @@ -82,7 +81,7 @@ impl PrivateArchive { pub fn files(&self) -> Vec<(PathBuf, Metadata)> { self.map .iter() - .map(|(path, (_, meta))| (path.clone(), meta.clone().into())) + .map(|(path, (_, meta))| (path.clone(), meta.clone())) .collect() } @@ -98,19 +97,13 @@ impl PrivateArchive { /// /// Returns an iterator over ([`PathBuf`], [`DataMapChunk`], [`Metadata`]) pub fn iter(&self) -> impl Iterator { - self.map.iter().map(|(path, (data_map, meta))| { - ( - path, - data_map, - match meta { - MetadataVersioned::V0(meta) => meta, - }, - ) - }) + self.map + .iter() + .map(|(path, (data_map, meta))| (path, data_map, meta)) } /// Get the underlying map - pub fn map(&self) -> &BTreeMap { + pub fn map(&self) -> &BTreeMap { &self.map } @@ -126,7 +119,7 @@ impl PrivateArchive { /// Serialize to bytes. pub fn to_bytes(&self) -> Result { let versioned = PrivateArchiveVersioned::V0(self.clone()); - let root_serialized = rmp_serde::to_vec(&versioned)?; + let root_serialized = rmp_serde::to_vec_named(&versioned)?; let root_serialized = Bytes::from(root_serialized); Ok(root_serialized) diff --git a/autonomi/src/client/high_level/files/archive_public.rs b/autonomi/src/client/high_level/files/archive_public.rs index eb5bb5930f..9b3823be40 100644 --- a/autonomi/src/client/high_level/files/archive_public.rs +++ b/autonomi/src/client/high_level/files/archive_public.rs @@ -27,7 +27,7 @@ use crate::{ Client, }; -use super::{Metadata, MetadataVersioned}; +use super::Metadata; /// The address of a public archive on the network. Points to an [`PublicArchive`]. pub type ArchiveAddr = XorName; @@ -36,7 +36,7 @@ pub type ArchiveAddr = XorName; /// to the network, of which the addresses are stored in this archive. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)] pub struct PublicArchive { - map: BTreeMap, + map: BTreeMap, } /// This type essentially wraps archive in version marker. E.g. in JSON format: @@ -76,8 +76,7 @@ impl PublicArchive { /// Add a file to a local archive /// Note that this does not upload the archive to the network pub fn add_file(&mut self, path: PathBuf, data_addr: DataAddr, meta: Metadata) { - self.map - .insert(path.clone(), (data_addr, MetadataVersioned::V0(meta))); + self.map.insert(path.clone(), (data_addr, meta)); debug!("Added a new file to the archive, path: {:?}", path); } @@ -85,7 +84,7 @@ impl PublicArchive { pub fn files(&self) -> Vec<(PathBuf, Metadata)> { self.map .iter() - .map(|(path, (_, meta))| (path.clone(), meta.clone().into())) + .map(|(path, (_, meta))| (path.clone(), meta.clone())) .collect() } @@ -97,19 +96,13 @@ impl PublicArchive { /// Iterate over the archive items /// Returns an iterator over (PathBuf, DataAddr, Metadata) pub fn iter(&self) -> impl Iterator { - self.map.iter().map(|(path, (addr, meta))| { - ( - path, - addr, - match meta { - MetadataVersioned::V0(meta) => meta, - }, - ) - }) + self.map + .iter() + .map(|(path, (addr, meta))| (path, addr, meta)) } /// Get the underlying map - pub fn map(&self) -> &BTreeMap { + pub fn map(&self) -> &BTreeMap { &self.map } @@ -125,7 +118,7 @@ impl PublicArchive { /// Serialize to bytes. pub fn to_bytes(&self) -> Result { let versioned = PublicArchiveVersioned::V0(self.clone()); - let root_serialized = rmp_serde::to_vec(&versioned)?; + let root_serialized = rmp_serde::to_vec_named(&versioned)?; let root_serialized = Bytes::from(root_serialized); Ok(root_serialized) @@ -229,7 +222,7 @@ mod test { // Create archive, forward compatible (still the same V0 version). let future_arch = FuturePublicArchiveVersioned::V0(arch.clone()); - let future_arch_serialized = rmp_serde::to_vec(&future_arch).unwrap(); + let future_arch_serialized = rmp_serde::to_vec_named(&future_arch).unwrap(); // Let's see if we can deserialize a (forward compatible) archive arriving to us from the future let _ = PublicArchive::from_bytes(Bytes::from(future_arch_serialized)).unwrap(); @@ -239,13 +232,13 @@ mod test { // Now we break forward compatibility by introducing a new version not supported by the old code. let future_arch = FuturePublicArchiveVersioned::V1(arch.clone()); - let future_arch_serialized = rmp_serde::to_vec(&future_arch).unwrap(); + let future_arch_serialized = rmp_serde::to_vec_named(&future_arch).unwrap(); // The old archive will not be able to decode this. assert!(PublicArchive::from_bytes(Bytes::from(future_arch_serialized)).is_err()); // Now we prove backwards compatibility. Our old V0 archive will still be decoded by our new archive wrapper as V0. let versioned_arch = PublicArchiveVersioned::V0(arch.clone()); // 'Old' archive wrapper - let versioned_arch_serialized = rmp_serde::to_vec(&versioned_arch).unwrap(); + let versioned_arch_serialized = rmp_serde::to_vec_named(&versioned_arch).unwrap(); let _: FuturePublicArchiveVersioned = // Into 'new' wrapper rmp_serde::from_slice(&versioned_arch_serialized[..]).unwrap(); } diff --git a/autonomi/src/client/high_level/files/mod.rs b/autonomi/src/client/high_level/files/mod.rs index 5c518faaf8..5ce0832eb6 100644 --- a/autonomi/src/client/high_level/files/mod.rs +++ b/autonomi/src/client/high_level/files/mod.rs @@ -44,47 +44,6 @@ pub struct Metadata { pub extra: Option, } -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[non_exhaustive] -#[serde(tag = "version")] -pub enum MetadataVersioned { - #[serde(rename = "0")] - V0(Metadata), -} - -// Allows us to access currently only possible `Metadata` struct (V0) conveniently: -// ```rust -// let metadata = MetadataVersioned::V0(Metadata::new_with_size(123)); -// let size = metadata.size; // Access the only possible (currently) `Metadata` (V0) struct -// ``` -impl std::ops::Deref for MetadataVersioned { - type Target = Metadata; - - fn deref(&self) -> &Self::Target { - let MetadataVersioned::V0(v0) = &self; - v0 - } -} -impl std::ops::DerefMut for MetadataVersioned { - fn deref_mut(&mut self) -> &mut Self::Target { - let MetadataVersioned::V0(v0) = self; - v0 - } -} - -impl From for MetadataVersioned { - fn from(value: Metadata) -> Self { - MetadataVersioned::V0(value) - } -} -// Again for convenience. When we add a `V1` we could implement an migration/upgrade path here: -// E.g. we could upgrade `V0` to `V1`, returning our latest/current `V1`. -impl From for Metadata { - fn from(MetadataVersioned::V0(value): MetadataVersioned) -> Self { - value - } -} - impl Metadata { /// Create a new metadata struct with the current time as uploaded, created and modified. pub fn new_with_size(size: u64) -> Self { From 9588a0542526674a2117f981b03c60e731efbb6f Mon Sep 17 00:00:00 2001 From: Benno Zeeman Date: Thu, 30 Jan 2025 09:44:03 +0100 Subject: [PATCH 4/5] test: forward compatibility for Metadata change --- .../high_level/files/archive_private.rs | 11 ----- .../client/high_level/files/archive_public.rs | 40 +++++++++++++++++++ 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/autonomi/src/client/high_level/files/archive_private.rs b/autonomi/src/client/high_level/files/archive_private.rs index 8e3f8599f9..2a9225bb0d 100644 --- a/autonomi/src/client/high_level/files/archive_private.rs +++ b/autonomi/src/client/high_level/files/archive_private.rs @@ -157,14 +157,3 @@ impl Client { result } } - -#[cfg(test)] -mod test { - #[test] - fn backwards_compatibility() { - let archive = super::PrivateArchive::new(); - let bytes = archive.to_bytes().unwrap(); - let archive2 = super::PrivateArchive::from_bytes(bytes).unwrap(); - assert_eq!(archive, archive2); - } -} diff --git a/autonomi/src/client/high_level/files/archive_public.rs b/autonomi/src/client/high_level/files/archive_public.rs index 9b3823be40..c9f0ad9f81 100644 --- a/autonomi/src/client/high_level/files/archive_public.rs +++ b/autonomi/src/client/high_level/files/archive_public.rs @@ -242,4 +242,44 @@ mod test { let _: FuturePublicArchiveVersioned = // Into 'new' wrapper rmp_serde::from_slice(&versioned_arch_serialized[..]).unwrap(); } + + #[test] + fn forward_compatibility() { + // What we do here is we create a new `Metadata` and use that in the `Archive` structs. + + /// A version `1.1` which is non-breaking (`1.0` is forward compatible with `1.1`). + #[derive(Debug, Default, Serialize, Deserialize)] + pub struct MetadataV1p1 { + created: u64, + modified: u64, + size: u64, + extra: Option, + accessed: Option, + } + #[derive(Debug, Default, Serialize, Deserialize)] + pub struct PublicArchiveV1p1 { + map: BTreeMap, + } + #[derive(Debug, Serialize, Deserialize)] + pub enum PublicArchiveVersionedV1p1 { + V0(PublicArchiveV1p1), + } + + let mut arch_p1 = PublicArchiveV1p1::default(); + arch_p1.map.insert( + PathBuf::from_str("hello_world").unwrap(), + ( + DataAddr::random(&mut rand::thread_rng()), + MetadataV1p1 { + accessed: Some(1), + ..Default::default() + }, + ), + ); + let arch_p1_ser = + rmp_serde::to_vec_named(&PublicArchiveVersionedV1p1::V0(arch_p1)).unwrap(); + + // Our old data structure should be forward compatible with the new one. + assert!(PublicArchive::from_bytes(Bytes::from(arch_p1_ser)).is_ok()); + } } From ac7c3e42366c27c3fcd560fbfac646be220ae896 Mon Sep 17 00:00:00 2001 From: Benno Zeeman Date: Thu, 30 Jan 2025 09:45:13 +0100 Subject: [PATCH 5/5] test: add doc to test --- autonomi/src/client/high_level/files/archive_public.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autonomi/src/client/high_level/files/archive_public.rs b/autonomi/src/client/high_level/files/archive_public.rs index c9f0ad9f81..fec5320444 100644 --- a/autonomi/src/client/high_level/files/archive_public.rs +++ b/autonomi/src/client/high_level/files/archive_public.rs @@ -254,7 +254,7 @@ mod test { modified: u64, size: u64, extra: Option, - accessed: Option, + accessed: Option, // Added field } #[derive(Debug, Default, Serialize, Deserialize)] pub struct PublicArchiveV1p1 {