From 6aec2609539c07a52cde1d0e1f5207703d23cab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Menci=C3=A8re?= <95620255+Nao-ris@users.noreply.github.com> Date: Thu, 19 Jun 2025 15:40:04 +0200 Subject: [PATCH 1/2] Improve & Test expiration --- src/document.rs | 14 +++++++------- src/fleece.rs | 2 +- src/lib.rs | 31 +++++++++++++++++++++++++++---- tests/document_tests.rs | 33 ++++++++++++++++++++++++++++----- 4 files changed, 63 insertions(+), 17 deletions(-) diff --git a/src/document.rs b/src/document.rs index d3c564c..e81bdd6 100644 --- a/src/document.rs +++ b/src/document.rs @@ -236,7 +236,7 @@ impl Database { } } - /// Returns the time, if any, at which a given document will expire and be purged. + /// Returns the time, if any, at which a given document will expire and be purged in milliseconds since the Unix epoch (1/1/1970.). /// Documents don't normally expire; you have to call `set_document_expiration` /// to set a document's expiration time. #[deprecated(note = "please use `document_expiration` on default collection instead")] @@ -250,7 +250,7 @@ impl Database { ); match exp { 0 => Ok(None), - _ if exp > 0 => Ok(Some(Timestamp(exp))), + _ if exp > 0 => Ok(Some(Timestamp::new(exp))), _ => failure(error), } } @@ -260,7 +260,7 @@ impl Database { #[deprecated(note = "please use `set_document_expiration` on default collection instead")] pub fn set_document_expiration(&mut self, doc_id: &str, when: Option) -> Result<()> { let exp: i64 = match when { - Some(Timestamp(n)) => n, + Some(Timestamp { timestamp }) => timestamp, _ => 0, }; unsafe { @@ -448,7 +448,7 @@ impl Collection { } } - /// Returns the time, if any, at which a given document will expire and be purged. + /// Returns the time, if any, at which a given document will expire and be purged in milliseconds since the Unix epoch (1/1/1970.). /// Documents don't normally expire; you have to call set_document_expiration /// to set a document's expiration time. pub fn document_expiration(&self, doc_id: &str) -> Result> { @@ -461,16 +461,16 @@ impl Collection { ); match exp { 0 => Ok(None), - _ if exp > 0 => Ok(Some(Timestamp(exp))), + _ if exp > 0 => Ok(Some(Timestamp::new(exp))), _ => failure(error), } } } - /// Sets or clears the expiration time of a document. + /// Sets or clears the expiration time of a document in milliseconds since the Unix epoch (1/1/1970.). pub fn set_document_expiration(&mut self, doc_id: &str, when: Option) -> Result<()> { let exp: i64 = match when { - Some(Timestamp(n)) => n, + Some(Timestamp { timestamp }) => timestamp, _ => 0, }; unsafe { diff --git a/src/fleece.rs b/src/fleece.rs index a73ba88..3045514 100644 --- a/src/fleece.rs +++ b/src/fleece.rs @@ -291,7 +291,7 @@ impl Value { if t == 0 { return None; } - Some(Timestamp(t)) + Some(Timestamp::new(t)) } } diff --git a/src/lib.rs b/src/lib.rs index 581d234..a6b10f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,11 +54,11 @@ mod c_api; use self::c_api::{ CBLListenerToken, CBLRefCounted, CBL_DumpInstances, CBL_InstanceCount, CBL_Release, CBL_Retain, - CBLListener_Remove, CBLITE_VERSION, + CBLListener_Remove, CBL_Now, CBLITE_VERSION, }; #[cfg(target_os = "android")] use self::c_api::{CBLError, CBLInitContext, CBL_Init}; -use std::ffi::CStr; +use std::{ffi::CStr, time::Duration}; //////// RE-EXPORT: @@ -78,9 +78,32 @@ pub trait CblRef { fn get_ref(&self) -> Self::Output; } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] /// A time value for document expiration. Defined as milliseconds since the Unix epoch (1/1/1970.) -pub struct Timestamp(pub i64); +pub struct Timestamp { + pub(crate) timestamp: i64, +} + +impl Timestamp { + pub fn now() -> Timestamp { + Timestamp { + timestamp: unsafe { CBL_Now() }, + } + } + + /// Create a Timestamp from milliseconds since the Unix epoch (1/1/1970.) + pub(crate) fn new(milliseconds_from_epoch: i64) -> Self { + Timestamp { + timestamp: milliseconds_from_epoch, + } + } + + pub fn add(&self, duration: Duration) -> Self { + Timestamp { + timestamp: self.timestamp + duration.as_millis() as i64, + } + } +} pub struct Listener { pub listener_token: ListenerToken, diff --git a/tests/document_tests.rs b/tests/document_tests.rs index 8c3a32d..1822aed 100644 --- a/tests/document_tests.rs +++ b/tests/document_tests.rs @@ -2,7 +2,7 @@ extern crate core; extern crate couchbase_lite; use self::couchbase_lite::*; -use std::time::Duration; +use std::{thread::sleep, time::Duration}; use utils::{init_logging, LeakChecker}; pub mod utils; @@ -296,12 +296,35 @@ fn database_document_expiration() { let mut document = Document::new_with_id("foo"); db.save_document_with_concurency_control(&mut document, ConcurrencyControl::FailOnConflict) .expect("save_document"); + + // No expiration by default let expiration = db.document_expiration("foo").expect("document_expiration"); assert!(expiration.is_none()); - db.set_document_expiration("foo", Some(Timestamp(1000000000))) + + // Set expiration in 2 seconds + let expiration = Timestamp::now().add(Duration::from_secs(2)); + db.set_document_expiration("foo", Some(expiration)) .expect("set_document_expiration"); - let expiration = db.document_expiration("foo").expect("document_expiration"); - assert!(expiration.is_some()); - assert_eq!(expiration.unwrap().0, 1000000000); + + // Check expiration is set up + let doc_expiration = db.document_expiration("foo").expect("document_expiration"); + assert_eq!(doc_expiration.unwrap(), expiration); + + // Check the document is still present after 1 second + sleep(Duration::from_secs(1)); + assert!(db.get_document("foo").is_ok()); + + // Move to expiration time + sleep(Duration::from_secs(1)); + + // Check documents disappears + for _ in 0..5 { + if db.get_document("foo").unwrap().is_deleted() { + return; + } + + sleep(Duration::from_secs(1)); + } + panic!("The document is still present 10 seconds after its expiration time"); }); } From 0ed1db244d232d4175406a07cadbf612534baf72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Menci=C3=A8re?= <95620255+Nao-ris@users.noreply.github.com> Date: Thu, 19 Jun 2025 15:47:00 +0200 Subject: [PATCH 2/2] Fix ut? --- tests/document_tests.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/document_tests.rs b/tests/document_tests.rs index 1822aed..01e5afa 100644 --- a/tests/document_tests.rs +++ b/tests/document_tests.rs @@ -319,7 +319,8 @@ fn database_document_expiration() { // Check documents disappears for _ in 0..5 { - if db.get_document("foo").unwrap().is_deleted() { + let doc = db.get_document("foo"); + if doc.is_err() || doc.unwrap().is_deleted() { return; }