Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions client/src/dbus/api/collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ impl<'a> Collection<'a> {
{
zbus::proxy::Builder::new(connection)
.path(object_path)?
.uncached_properties(&["Label", "Modified"])
.build()
.await
.map_err(From::from)
Expand Down
1 change: 1 addition & 0 deletions client/src/dbus/api/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ impl<'a> Item<'a> {
{
zbus::proxy::Builder::new(connection)
.path(object_path)?
.uncached_properties(&["Label", "Attributes", "Modified"])
.build()
.await
.map_err(From::from)
Expand Down
46 changes: 46 additions & 0 deletions client/src/dbus/collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,4 +306,50 @@ mod tests {
let service = Service::encrypted().await.unwrap();
create_item(service, true).await;
}

#[tokio::test]
async fn test_attribute_search_patterns() {
let service = Service::plain().await.unwrap();
let collection = service.default_collection().await.unwrap();

let secret = crate::Secret::text("search test");

// Create items with different attributes
let attrs1 = HashMap::from([("service", "email"), ("username", "user1")]);
let item1 = collection
.create_item("Email 1", &attrs1, secret.clone(), true, None)
.await
.unwrap();

let attrs2 = HashMap::from([("service", "email"), ("username", "user2")]);
let item2 = collection
.create_item("Email 2", &attrs2, secret.clone(), true, None)
.await
.unwrap();

let attrs3 = HashMap::from([("service", "web"), ("username", "user1")]);
let item3 = collection
.create_item("Web", &attrs3, secret.clone(), true, None)
.await
.unwrap();

// Search by service
let search_email = HashMap::from([("service", "email")]);
let email_items = collection.search_items(&search_email).await.unwrap();
assert!(email_items.len() >= 2);

// Search by username
let search_user1 = HashMap::from([("username", "user1")]);
let user1_items = collection.search_items(&search_user1).await.unwrap();
assert!(user1_items.len() >= 2);

// Search by both attributes
let search_specific = HashMap::from([("service", "email"), ("username", "user1")]);
let specific_items = collection.search_items(&search_specific).await.unwrap();
assert!(specific_items.len() >= 1);

item1.delete(None).await.unwrap();
item2.delete(None).await.unwrap();
item3.delete(None).await.unwrap();
}
}
141 changes: 141 additions & 0 deletions client/src/dbus/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,144 @@ impl<'a> Item<'a> {
self.inner.inner().path()
}
}

#[cfg(test)]
#[cfg(feature = "tokio")]
mod tests {
use std::collections::HashMap;

use crate::dbus::Service;

#[tokio::test]
async fn test_item_label_mutation() {
let service = Service::plain().await.unwrap();
let collection = service.default_collection().await.unwrap();

let attributes = HashMap::from([("test", "label-mutation")]);
let secret = crate::Secret::text("test secret");

let item = collection
.create_item("Original Label", &attributes, secret, true, None)
.await
.unwrap();

let initial_label = item.label().await.unwrap();
assert_eq!(initial_label, "Original Label");

item.set_label("Updated Label").await.unwrap();

let updated_label = item.label().await.unwrap();
assert_eq!(updated_label, "Updated Label");

item.delete(None).await.unwrap();
}

#[tokio::test]
async fn test_item_secret_mutation() {
let service = Service::plain().await.unwrap();
let collection = service.default_collection().await.unwrap();

let attributes = HashMap::from([("test", "secret-mutation")]);
let original_secret = crate::Secret::text("original secret");

let item = collection
.create_item(
"Secret Test",
&attributes,
original_secret.clone(),
true,
None,
)
.await
.unwrap();

assert_eq!(item.secret().await.unwrap(), original_secret);

let new_secret = crate::Secret::text("updated secret");
item.set_secret(new_secret.clone()).await.unwrap();

assert_eq!(item.secret().await.unwrap(), new_secret);

item.delete(None).await.unwrap();
}

#[tokio::test]
async fn test_text_secret_type() {
let service = Service::plain().await.unwrap();
let collection = service.default_collection().await.unwrap();

let text_attributes = HashMap::from([("type", "text-secret")]);
let text_secret = crate::Secret::text("text password");
let text_item = collection
.create_item(
"Text Secret",
&text_attributes,
text_secret.clone(),
true,
None,
)
.await
.unwrap();

assert_eq!(text_item.secret().await.unwrap(), text_secret);
text_item.delete(None).await.unwrap();
}

#[tokio::test]
async fn test_blob_secret_type() {
let service = Service::plain().await.unwrap();
let collection = service.default_collection().await.unwrap();

let blob_attributes = HashMap::from([("type", "blob-secret")]);
let blob_secret = crate::Secret::blob(b"binary data");
let blob_item = collection
.create_item(
"Blob Secret",
&blob_attributes,
blob_secret.clone(),
true,
None,
)
.await
.unwrap();

let retrieved_secret = blob_item.secret().await.unwrap();

// TODO: gnome-keyring doesn't preserve content types - everything becomes
// text/plain But the actual secret data should be preserved
assert_eq!(retrieved_secret.as_bytes(), blob_secret.as_bytes());
blob_item.delete(None).await.unwrap();
}

#[tokio::test]
async fn test_item_timestamps() {
let service = Service::plain().await.unwrap();
let collection = service.default_collection().await.unwrap();

let attributes = HashMap::from([("test", "timestamps")]);
let secret = crate::Secret::text("timestamp test");

let item = collection
.create_item("Timestamp Test", &attributes, secret, true, None)
.await
.unwrap();

let created = item.created().await.unwrap();
let modified = item.modified().await.unwrap();

eprintln!("Created: {:?}, Modified: {:?}", created, modified);
assert_eq!(created, modified);

tokio::time::sleep(std::time::Duration::from_secs(1)).await;
item.set_label("Updated Label").await.unwrap();

// Allow time for D-Bus changes to propagate
tokio::time::sleep(std::time::Duration::from_millis(100)).await;

let new_modified = item.modified().await.unwrap();
assert!(new_modified > modified);
assert_eq!(item.created().await.unwrap(), created);

item.delete(None).await.unwrap();
}
}