chore: test refactor

This commit is contained in:
kaichaosun 2026-06-18 12:48:10 +08:00
parent 8835492d6f
commit a5d760468a
No known key found for this signature in database
GPG Key ID: 223E0F992F4F03BF
5 changed files with 55 additions and 41 deletions

View File

@ -20,6 +20,12 @@ impl TestLogosAccount {
verifying_key,
}
}
/// This account's cryptographic id: the hex of its verifying key. This is
/// what a credential carries and what `validate_sender` resolves to
pub fn iden_id(&self) -> IdentId {
IdentId::new(hex::encode(self.verifying_key.as_ref()))
}
}
impl IdentityProvider for TestLogosAccount {

View File

@ -20,12 +20,6 @@ pub struct Content {
pub struct ConvoOutcome {
pub convo_id: ConversationId,
pub content: Option<Content>,
/// The *unvalidated* sender credential for `content`: the claimed Account
/// and the device (LocalIdentity) it was sent from. The device key is
/// MLS-authenticated, but the account claim must be validated against an
/// [`AccountService`](logos_account::AccountService) before it is trusted.
/// `None` for control messages (e.g. MLS commits) carrying no application
/// content, and for conversation types that don't yet surface a credential.
pub credential: Option<SenderCredential>,
}

View File

@ -41,13 +41,15 @@ pub struct ReceivedMessage<T> {
pub struct TestClient {
inner: ClientType,
received_messages: Vec<ReceivedMessage<Vec<u8>>>,
sender_identity: MessageSender,
}
impl TestClient {
fn init(client: ClientType) -> Self {
fn init(client: ClientType, sender_identity: MessageSender) -> Self {
Self {
inner: client,
received_messages: vec![],
sender_identity,
}
}
@ -55,6 +57,10 @@ impl TestClient {
self.inner.ident_id().clone()
}
pub fn as_sender(&self) -> MessageSender {
self.sender_identity.clone()
}
fn drain_outcomes(&mut self) -> Vec<PayloadOutcome> {
let mut messages = vec![];
while let Some(data) = self.inner.ds().poll() {
@ -102,9 +108,9 @@ impl TestClient {
&self.received_messages
}
pub fn check(&self, convo_id: &str, content: &[u8]) -> bool {
pub fn check(&self, convo_id: &str, content: &[u8], sender: Option<MessageSender>) -> bool {
for msg in &self.received_messages {
if msg.convo_id == convo_id && msg.contents == content {
if msg.convo_id == convo_id && msg.contents == content && msg.sender == sender {
return true;
}
}
@ -172,11 +178,16 @@ impl<const N: usize> TestHarness<N> {
let ident = TestLogosAccount::new(Self::names(i));
addresses.insert(i, ident.id().clone());
let iden_id = ident.iden_id();
let sender_identity = MessageSender {
account: iden_id.clone(),
local_identity: iden_id,
};
let core_client =
ClientType::new_with_name(ident, ds.clone(), rs.clone(), wp, MemStore::new())
.unwrap();
let client = TestClient::init(core_client);
let client = TestClient::init(core_client, sender_identity);
clients.push(client);
}
@ -348,6 +359,8 @@ mod tests {
harness.process(Duration::from_millis(200));
assert!(harness.raya().check(&convo_id, b"Hello"))
// GroupV2 (de-mls) carries no account-bound credential yet, so the
// sender can't be validated — it resolves to `None`.
assert!(harness.raya().check(&convo_id, b"Hello", None))
}
}

View File

@ -49,35 +49,36 @@ fn create_group() {
.expect("Pax send");
harness.process(Duration::from_millis(500));
assert!(harness.saro().check(&convo_id, M_R1));
assert!(harness.saro().check(&convo_id, M_P1));
// The sender a recipient resolves each author to — the key-based identity,
// captured from the account (not the display name in `ident_id`).
let raya_sender = harness.raya().as_sender();
let pax_sender = harness.pax().as_sender();
assert!(!harness.raya().check(&convo_id, M_R1));
assert!(harness.raya().check(&convo_id, M_P1));
// Each message must arrive *and* carry the validated sender of its author:
// M_R1 from Raya, M_P1 from Pax.
assert!(
harness
.saro()
.check(&convo_id, M_R1, Some(raya_sender.clone()))
);
assert!(harness.saro().check(&convo_id, M_P1, Some(pax_sender.clone())));
assert!(!harness.pax().check(&convo_id, M_R1));
assert!(!harness.pax().check(&convo_id, M_P1));
assert!(
!harness
.raya()
.check(&convo_id, M_R1, Some(raya_sender.clone()))
);
assert!(harness.raya().check(&convo_id, M_P1, Some(pax_sender.clone())));
// Every delivered message carries a verified sender: both the Account and
// the LocalIdentity it was sent from. On testnet each identity is its own
// single-device account, so the two resolve to the same key.
let raya_sender = harness
.saro()
.sender_of(&convo_id, M_R1)
.expect("Saro should see who sent Raya's message")
.clone();
assert!(!harness.pax().check(&convo_id, M_R1, Some(raya_sender.clone())));
assert!(!harness.pax().check(&convo_id, M_P1, Some(pax_sender.clone())));
// Single-key testnet account: account and local identity are the same key.
assert_eq!(
raya_sender.account, raya_sender.local_identity,
"single-key testnet account resolves Account == LocalIdentity"
);
let pax_sender = harness
.saro()
.sender_of(&convo_id, M_P1)
.expect("Saro should see who sent Pax's message")
.clone();
// Distinct identities resolve to distinct senders — the basis for telling
// Distinct identities resolve to distinct accounts — the basis for telling
// group members apart and for collapsing an account's devices to one Account.
assert_ne!(
raya_sender.account, pax_sender.account,

View File

@ -32,12 +32,12 @@ fn groupv2_2way_roundtrip() {
.send_content(&convo_id, S_M1)
.expect("saro send");
harness.process_until(|h| h.raya().check(&convo_id, S_M1));
harness.process_until(|h| h.raya().check(&convo_id, S_M1, None));
// Raya replies; settle until Saro receives it.
info!(target: "chat", "Raya -> sending:{R_M1:?}");
harness.raya().send_content(&convo_id, R_M1).unwrap();
harness.process_until(|h| h.saro().check(&convo_id, R_M1));
harness.process_until(|h| h.saro().check(&convo_id, R_M1, None));
}
#[test]
@ -70,7 +70,7 @@ fn core_client() {
.send_content(&convo_id, S_M1)
.expect("saro send");
harness.process_until_label("Recv S_M1", |h| h.raya().check(&convo_id, S_M1));
harness.process_until_label("Recv S_M1", |h| h.raya().check(&convo_id, S_M1, None));
// Raya replies; settle until Saro receives it.
info!(target: "chat", "Raya -> sending: {R_M1:?}");
@ -79,7 +79,7 @@ fn core_client() {
.send_content(&convo_id, R_M1)
.expect("raya send");
harness.process_until_label("Recv R_M1", |h| h.saro().check(&convo_id, R_M1));
harness.process_until_label("Recv R_M1", |h| h.saro().check(&convo_id, R_M1, None));
// Raya (a non-creator) invites Pax; settle until Pax has joined.
let particpants = &[&harness.pax().addr()];
@ -96,7 +96,7 @@ fn core_client() {
harness.saro().send_content(&convo_id, S_M2).unwrap();
harness.process_until_label("epoch check", |h| {
h.raya().check(&convo_id, S_M2) && h.pax().check(&convo_id, S_M2)
h.raya().check(&convo_id, S_M2, None) && h.pax().check(&convo_id, S_M2, None)
});
}
@ -171,8 +171,8 @@ fn core_client_four_members_two_epochs() {
.expect("Saro send");
harness.process_until_label("all chats converge", |h| {
h.raya().check(&convo_id, MSG)
&& h.pax().check(&convo_id, MSG)
&& h.mira().check(&convo_id, MSG)
h.raya().check(&convo_id, MSG, None)
&& h.pax().check(&convo_id, MSG, None)
&& h.mira().check(&convo_id, MSG, None)
});
}