use anyhow::Result;
use pubky_messenger::PrivateMessengerClient;
use std::fs;
async fn load_client(pkarr_file: &str, password: &str) -> Result<PrivateMessengerClient> {
let recovery_file_bytes = fs::read(pkarr_file)?;
let client = PrivateMessengerClient::from_recovery_file(&recovery_file_bytes, Some(password))?;
client.sign_in().await?;
Ok(client)
}
#[tokio::test]
async fn test_delete_message() -> Result<()> {
let client1 = load_client("p1.pkarr", "password").await?;
let client2 = load_client("p2.pkarr", "password").await?;
let client2_pubky = client2.public_key();
let messages_initial = client1.get_messages(&client2_pubky).await?;
let initial_count = messages_initial.len();
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)?
.as_millis();
let message_content = format!("Test message to be deleted [{}]", timestamp);
let message_id = client1.send_message(&client2_pubky, &message_content).await?;
tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
let messages_before = client1.get_messages(&client2_pubky).await?;
assert_eq!(
messages_before.len(),
initial_count + 1,
"Should have one more message after sending"
);
let our_message_exists = messages_before
.iter()
.any(|msg| msg.content == message_content);
assert!(our_message_exists, "Our message should exist before deletion");
client1.delete_message(&message_id, &client2_pubky).await?;
tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
let messages_after = client1.get_messages(&client2_pubky).await?;
assert_eq!(
messages_after.len(),
initial_count,
"Should return to initial message count after deletion"
);
let deleted_message_exists = messages_after
.iter()
.any(|msg| msg.content == message_content);
assert!(
!deleted_message_exists,
"Deleted message should not exist in the conversation"
);
Ok(())
}
#[tokio::test]
async fn test_delete_messages() -> Result<()> {
let client1 = load_client("p1.pkarr", "password").await?;
let client2 = load_client("p2.pkarr", "password").await?;
let client2_pubky = client2.public_key();
let messages_initial = client1.get_messages(&client2_pubky).await?;
let initial_count = messages_initial.len();
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)?
.as_millis();
let msg1 = format!("Message 1 to delete [{}]", timestamp);
let msg2 = format!("Message 2 to delete [{}]", timestamp);
let msg3 = format!("Message 3 to delete [{}]", timestamp);
let keep_msg = format!("Message to keep [{}]", timestamp);
let message_ids = vec![
client1.send_message(&client2_pubky, &msg1).await?,
client1.send_message(&client2_pubky, &msg2).await?,
client1.send_message(&client2_pubky, &msg3).await?,
];
client1.send_message(&client2_pubky, &keep_msg).await?;
tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
let messages_before = client1.get_messages(&client2_pubky).await?;
assert_eq!(
messages_before.len(),
initial_count + 4,
"Should have 4 more messages after sending"
);
client1.delete_messages(message_ids.clone(), &client2_pubky).await?;
tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
let messages_after = client1.get_messages(&client2_pubky).await?;
assert_eq!(
messages_after.len(),
initial_count + 1,
"Should have only the kept message plus initial messages"
);
let kept_message_exists = messages_after
.iter()
.any(|msg| msg.content == keep_msg);
assert!(
kept_message_exists,
"Message that wasn't deleted should still exist"
);
let deleted_messages = [msg1, msg2, msg3];
for deleted_content in &deleted_messages {
let exists = messages_after
.iter()
.any(|msg| msg.content == *deleted_content);
assert!(!exists, "Deleted message '{}' should not exist", deleted_content);
}
Ok(())
}
#[tokio::test]
async fn test_clear_messages() -> Result<()> {
let client1 = load_client("p1.pkarr", "password").await?;
let client2 = load_client("p2.pkarr", "password").await?;
let client2_pubky = client2.public_key();
let client1_pubky = client1.public_key();
for i in 1..=5 {
client1.send_message(&client2_pubky, &format!("Message {} from client1", i)).await?;
}
for i in 1..=3 {
client2.send_message(&client1_pubky, &format!("Message {} from client2", i)).await?;
}
let messages_before = client1.get_messages(&client2_pubky).await?;
let initial_count = messages_before.len();
assert!(initial_count >= 5, "Should have at least 5 messages total");
let client1_messages_count = messages_before
.iter()
.filter(|msg| msg.sender == client1.public_key_string())
.count();
assert!(client1_messages_count >= 5, "Should have at least 5 messages from client1");
client1.clear_messages(&client2_pubky).await?;
let messages_after = client1.get_messages(&client2_pubky).await?;
let client1_messages_after = messages_after
.iter()
.filter(|msg| msg.sender == client1.public_key_string())
.count();
assert_eq!(
client1_messages_after, 0,
"All messages sent by client1 should be deleted"
);
let client2_messages_after = messages_after
.iter()
.filter(|msg| msg.sender == client2.public_key_string())
.count();
assert_eq!(
messages_after.len(),
client2_messages_after,
"Only messages from client2 should remain"
);
Ok(())
}
#[tokio::test]
async fn test_delete_non_existent_message() -> Result<()> {
let client1 = load_client("p1.pkarr", "password").await?;
let client2 = load_client("p2.pkarr", "password").await?;
let client2_pubky = client2.public_key();
let fake_message_id = "00000000-0000-0000-0000-000000000000";
let result = client1.delete_message(fake_message_id, &client2_pubky).await;
match result {
Ok(_) => {
assert!(true, "Delete of non-existent message succeeded silently");
}
Err(e) => {
println!("Expected error for non-existent message: {}", e);
assert!(true, "Delete of non-existent message returned error as expected");
}
}
Ok(())
}
#[tokio::test]
async fn test_clear_empty_conversation() -> Result<()> {
let client1 = load_client("p1.pkarr", "password").await?;
let random_keypair = pkarr::Keypair::random();
let random_pubky = random_keypair.public_key();
let result = client1.clear_messages(&random_pubky).await;
assert!(
result.is_ok(),
"Clearing an empty conversation should succeed"
);
Ok(())
}
#[tokio::test]
async fn test_delete_messages_with_empty_list() -> Result<()> {
let client1 = load_client("p1.pkarr", "password").await?;
let client2 = load_client("p2.pkarr", "password").await?;
let client2_pubky = client2.public_key();
let empty_ids: Vec<String> = vec![];
let result = client1.delete_messages(empty_ids, &client2_pubky).await;
assert!(
result.is_ok(),
"Deleting with empty list should succeed (no-op)"
);
Ok(())
}
#[tokio::test]
async fn test_delete_mixed_valid_invalid_ids() -> Result<()> {
let client1 = load_client("p1.pkarr", "password").await?;
let client2 = load_client("p2.pkarr", "password").await?;
let client2_pubky = client2.public_key();
let valid_id = client1.send_message(&client2_pubky, "Valid message").await?;
let mixed_ids = vec![
valid_id.clone(),
"00000000-0000-0000-0000-000000000000".to_string(),
"invalid-id-format".to_string(),
];
let messages_before = client1.get_messages(&client2_pubky).await?;
let initial_count = messages_before.len();
let result = client1.delete_messages(mixed_ids, &client2_pubky).await;
match result {
Ok(_) => {
let messages_after = client1.get_messages(&client2_pubky).await?;
assert!(
messages_after.len() < initial_count,
"Valid message should have been deleted"
);
}
Err(e) => {
println!("Mixed delete failed as expected: {}", e);
}
}
Ok(())
}