mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-05-16 12:43:01 -04:00
Merge pull request #4428 from matrix-org/valere/insta_rs_snapshot_testing
test(snapshot): Use snapshot testing in sdk-common
This commit is contained in:
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
@@ -18,6 +18,9 @@ concurrency:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
# Insta.rs is run directly via cargo test. We don't want insta.rs to create new snapshots files.
|
||||
# Just want it to run the tests (option `no` instead of `auto`).
|
||||
INSTA_UPDATE: no
|
||||
|
||||
jobs:
|
||||
xtask:
|
||||
|
||||
@@ -30,6 +30,33 @@ integration tests that need a running synapse instance. These tests reside in
|
||||
synapse for testing purposes.
|
||||
|
||||
|
||||
### Snapshot Testing
|
||||
|
||||
You can add/review snapshot tests using [insta.rs](https://insta.rs)
|
||||
|
||||
Every new struct/enum that derives `Serialize` `Deserialise` should have a snapshot test for it.
|
||||
Any code change that breaks serialisation will then break a test, the author will then have to decide
|
||||
how to handle migration and test it if needed.
|
||||
|
||||
|
||||
And for an improved review experience it's recommended (but not necessary) to install the cargo-insta tool:
|
||||
|
||||
Unix:
|
||||
```
|
||||
curl -LsSf https://insta.rs/install.sh | sh
|
||||
```
|
||||
|
||||
Windows:
|
||||
```
|
||||
powershell -c "irm https://insta.rs/install.ps1 | iex"
|
||||
```
|
||||
|
||||
Usual flow is to first run the test, then review them.
|
||||
```
|
||||
cargo insta test
|
||||
cargo insta review
|
||||
```
|
||||
|
||||
## Pull requests
|
||||
|
||||
Ideally, a PR should have a *proper title*, with *atomic logical commits*, and
|
||||
|
||||
20
Cargo.lock
generated
20
Cargo.lock
generated
@@ -2595,6 +2595,19 @@ dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "insta"
|
||||
version = "1.41.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e9ffc4d4892617c50a928c52b2961cb5174b6fc6ebf252b2fac9d21955c48b8"
|
||||
dependencies = [
|
||||
"console",
|
||||
"lazy_static",
|
||||
"linked-hash-map",
|
||||
"serde",
|
||||
"similar",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.13"
|
||||
@@ -2789,6 +2802,12 @@ dependencies = [
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.14"
|
||||
@@ -3170,6 +3189,7 @@ dependencies = [
|
||||
"getrandom",
|
||||
"gloo-timers",
|
||||
"imbl",
|
||||
"insta",
|
||||
"js-sys",
|
||||
"matrix-sdk-test-macros",
|
||||
"proptest",
|
||||
|
||||
@@ -46,6 +46,7 @@ hmac = "0.12.1"
|
||||
http = "1.1.0"
|
||||
imbl = "3.0.0"
|
||||
indexmap = "2.6.0"
|
||||
insta = { version = "1.41.1", features = ["json"] }
|
||||
itertools = "0.13.0"
|
||||
js-sys = "0.3.69"
|
||||
mime = "0.3.17"
|
||||
@@ -124,6 +125,9 @@ debug = 0
|
||||
# for the extra time of optimizing it for a clean build of matrix-sdk-ffi.
|
||||
quote = { opt-level = 2 }
|
||||
sha2 = { opt-level = 2 }
|
||||
# faster runs for insta.rs snapshot testing
|
||||
insta.opt-level = 3
|
||||
similar.opt-level = 3
|
||||
|
||||
# Custom profile with full debugging info, use `--profile dbg` to select
|
||||
[profile.dbg]
|
||||
|
||||
@@ -46,6 +46,7 @@ assert_matches = { workspace = true }
|
||||
proptest = { workspace = true }
|
||||
matrix-sdk-test-macros = { path = "../../testing/matrix-sdk-test-macros" }
|
||||
wasm-bindgen-test = { workspace = true }
|
||||
insta = { workspace = true }
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
# Enable the test macro.
|
||||
|
||||
@@ -909,21 +909,22 @@ mod tests {
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use assert_matches::assert_matches;
|
||||
use insta::{assert_json_snapshot, with_settings};
|
||||
use ruma::{
|
||||
event_id,
|
||||
device_id, event_id,
|
||||
events::{room::message::RoomMessageEventContent, AnySyncTimelineEvent},
|
||||
serde::Raw,
|
||||
user_id,
|
||||
user_id, DeviceKeyAlgorithm,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use serde_json::json;
|
||||
|
||||
use super::{
|
||||
AlgorithmInfo, DecryptedRoomEvent, EncryptionInfo, SyncTimelineEvent, TimelineEvent,
|
||||
TimelineEventKind, UnableToDecryptInfo, UnableToDecryptReason, UnsignedDecryptionResult,
|
||||
UnsignedEventLocation, VerificationState, WithheldCode,
|
||||
AlgorithmInfo, DecryptedRoomEvent, DeviceLinkProblem, EncryptionInfo, ShieldState,
|
||||
ShieldStateCode, SyncTimelineEvent, TimelineEvent, TimelineEventKind, UnableToDecryptInfo,
|
||||
UnableToDecryptReason, UnsignedDecryptionResult, UnsignedEventLocation, VerificationLevel,
|
||||
VerificationState, WithheldCode,
|
||||
};
|
||||
use crate::deserialized_responses::{DeviceLinkProblem, ShieldStateCode, VerificationLevel};
|
||||
|
||||
fn example_event() -> serde_json::Value {
|
||||
json!({
|
||||
@@ -1317,4 +1318,129 @@ mod tests {
|
||||
let reason = UnableToDecryptReason::UnknownMegolmMessageIndex;
|
||||
assert!(reason.is_missing_room_key());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_test_verification_level() {
|
||||
assert_json_snapshot!(VerificationLevel::VerificationViolation);
|
||||
assert_json_snapshot!(VerificationLevel::UnsignedDevice);
|
||||
assert_json_snapshot!(VerificationLevel::None(DeviceLinkProblem::InsecureSource));
|
||||
assert_json_snapshot!(VerificationLevel::None(DeviceLinkProblem::MissingDevice));
|
||||
assert_json_snapshot!(VerificationLevel::UnverifiedIdentity);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_test_verification_states() {
|
||||
assert_json_snapshot!(VerificationState::Unverified(VerificationLevel::UnsignedDevice));
|
||||
assert_json_snapshot!(VerificationState::Unverified(
|
||||
VerificationLevel::VerificationViolation
|
||||
));
|
||||
assert_json_snapshot!(VerificationState::Unverified(VerificationLevel::None(
|
||||
DeviceLinkProblem::InsecureSource,
|
||||
)));
|
||||
assert_json_snapshot!(VerificationState::Unverified(VerificationLevel::None(
|
||||
DeviceLinkProblem::MissingDevice,
|
||||
)));
|
||||
assert_json_snapshot!(VerificationState::Verified);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_test_shield_states() {
|
||||
assert_json_snapshot!(ShieldState::None);
|
||||
assert_json_snapshot!(ShieldState::Red {
|
||||
code: ShieldStateCode::UnverifiedIdentity,
|
||||
message: "a message"
|
||||
});
|
||||
assert_json_snapshot!(ShieldState::Grey {
|
||||
code: ShieldStateCode::AuthenticityNotGuaranteed,
|
||||
message: "authenticity of this message cannot be guaranteed",
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_test_shield_codes() {
|
||||
assert_json_snapshot!(ShieldStateCode::AuthenticityNotGuaranteed);
|
||||
assert_json_snapshot!(ShieldStateCode::UnknownDevice);
|
||||
assert_json_snapshot!(ShieldStateCode::UnsignedDevice);
|
||||
assert_json_snapshot!(ShieldStateCode::UnverifiedIdentity);
|
||||
assert_json_snapshot!(ShieldStateCode::SentInClear);
|
||||
assert_json_snapshot!(ShieldStateCode::VerificationViolation);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_test_algorithm_info() {
|
||||
let mut map = BTreeMap::new();
|
||||
map.insert(DeviceKeyAlgorithm::Curve25519, "claimedclaimedcurve25519".to_owned());
|
||||
map.insert(DeviceKeyAlgorithm::Ed25519, "claimedclaimeded25519".to_owned());
|
||||
let info = AlgorithmInfo::MegolmV1AesSha2 {
|
||||
curve25519_key: "curvecurvecurve".into(),
|
||||
sender_claimed_keys: BTreeMap::from([
|
||||
(DeviceKeyAlgorithm::Curve25519, "claimedclaimedcurve25519".to_owned()),
|
||||
(DeviceKeyAlgorithm::Ed25519, "claimedclaimeded25519".to_owned()),
|
||||
]),
|
||||
};
|
||||
|
||||
assert_json_snapshot!(info)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_test_encryption_info() {
|
||||
let info = EncryptionInfo {
|
||||
sender: user_id!("@alice:localhost").to_owned(),
|
||||
sender_device: Some(device_id!("ABCDEFGH").to_owned()),
|
||||
algorithm_info: AlgorithmInfo::MegolmV1AesSha2 {
|
||||
curve25519_key: "curvecurvecurve".into(),
|
||||
sender_claimed_keys: Default::default(),
|
||||
},
|
||||
verification_state: VerificationState::Verified,
|
||||
};
|
||||
|
||||
with_settings!({sort_maps =>true}, {
|
||||
assert_json_snapshot!(info)
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_test_sync_timeline_event() {
|
||||
let room_event = SyncTimelineEvent {
|
||||
kind: TimelineEventKind::Decrypted(DecryptedRoomEvent {
|
||||
event: Raw::new(&example_event()).unwrap().cast(),
|
||||
encryption_info: EncryptionInfo {
|
||||
sender: user_id!("@sender:example.com").to_owned(),
|
||||
sender_device: Some(device_id!("ABCDEFGHIJ").to_owned()),
|
||||
algorithm_info: AlgorithmInfo::MegolmV1AesSha2 {
|
||||
curve25519_key: "xxx".to_owned(),
|
||||
sender_claimed_keys: BTreeMap::from([
|
||||
(
|
||||
DeviceKeyAlgorithm::Ed25519,
|
||||
"I3YsPwqMZQXHkSQbjFNEs7b529uac2xBpI83eN3LUXo".to_owned(),
|
||||
),
|
||||
(
|
||||
DeviceKeyAlgorithm::Curve25519,
|
||||
"qzdW3F5IMPFl0HQgz5w/L5Oi/npKUFn8Um84acIHfPY".to_owned(),
|
||||
),
|
||||
]),
|
||||
},
|
||||
verification_state: VerificationState::Verified,
|
||||
},
|
||||
unsigned_encryption_info: Some(BTreeMap::from([(
|
||||
UnsignedEventLocation::RelationsThreadLatestEvent,
|
||||
UnsignedDecryptionResult::UnableToDecrypt(UnableToDecryptInfo {
|
||||
session_id: Some("xyz".to_owned()),
|
||||
reason: UnableToDecryptReason::MissingMegolmSession {
|
||||
withheld_code: Some(WithheldCode::Unverified),
|
||||
},
|
||||
}),
|
||||
)])),
|
||||
}),
|
||||
push_actions: Default::default(),
|
||||
};
|
||||
|
||||
with_settings!({sort_maps =>true}, {
|
||||
// We use directly the serde_json formatter here, because of a bug in insta
|
||||
// not serializing custom BTreeMap key enum https://github.com/mitsuhiko/insta/issues/689
|
||||
assert_json_snapshot! {
|
||||
serde_json::to_value(&room_event).unwrap(),
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
source: crates/matrix-sdk-common/src/deserialized_responses.rs
|
||||
expression: info
|
||||
---
|
||||
{
|
||||
"MegolmV1AesSha2": {
|
||||
"curve25519_key": "curvecurvecurve",
|
||||
"sender_claimed_keys": {
|
||||
"ed25519": "claimedclaimeded25519",
|
||||
"curve25519": "claimedclaimedcurve25519"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
source: crates/matrix-sdk-common/src/deserialized_responses.rs
|
||||
expression: info
|
||||
---
|
||||
{
|
||||
"sender": "@alice:localhost",
|
||||
"sender_device": "ABCDEFGH",
|
||||
"algorithm_info": {
|
||||
"MegolmV1AesSha2": {
|
||||
"curve25519_key": "curvecurvecurve",
|
||||
"sender_claimed_keys": {}
|
||||
}
|
||||
},
|
||||
"verification_state": "Verified"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
source: crates/matrix-sdk-common/src/deserialized_responses.rs
|
||||
expression: "serde_json::to_value(&code).unwrap()"
|
||||
---
|
||||
"UnknownDevice"
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
source: crates/matrix-sdk-common/src/deserialized_responses.rs
|
||||
expression: "serde_json::to_value(&code).unwrap()"
|
||||
---
|
||||
"UnsignedDevice"
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
source: crates/matrix-sdk-common/src/deserialized_responses.rs
|
||||
expression: "serde_json::to_value(&code).unwrap()"
|
||||
---
|
||||
"UnverifiedIdentity"
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
source: crates/matrix-sdk-common/src/deserialized_responses.rs
|
||||
expression: "serde_json::to_value(&code).unwrap()"
|
||||
---
|
||||
"SentInClear"
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
source: crates/matrix-sdk-common/src/deserialized_responses.rs
|
||||
expression: "serde_json::to_value(&code).unwrap()"
|
||||
---
|
||||
"VerificationViolation"
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
source: crates/matrix-sdk-common/src/deserialized_responses.rs
|
||||
expression: "serde_json::to_value(&code).unwrap()"
|
||||
---
|
||||
"AuthenticityNotGuaranteed"
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: crates/matrix-sdk-common/src/deserialized_responses.rs
|
||||
expression: "serde_json::to_value(&state).unwrap()"
|
||||
---
|
||||
{
|
||||
"Red": {
|
||||
"code": "UnverifiedIdentity",
|
||||
"message": "a message"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: crates/matrix-sdk-common/src/deserialized_responses.rs
|
||||
expression: "serde_json::to_value(&state).unwrap()"
|
||||
---
|
||||
{
|
||||
"Grey": {
|
||||
"code": "AuthenticityNotGuaranteed",
|
||||
"message": "authenticity of this message cannot be guaranteed"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
source: crates/matrix-sdk-common/src/deserialized_responses.rs
|
||||
expression: "serde_json::to_value(&state).unwrap()"
|
||||
---
|
||||
"None"
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
source: crates/matrix-sdk-common/src/deserialized_responses.rs
|
||||
expression: "serde_json::to_value(&room_event).unwrap()"
|
||||
---
|
||||
{
|
||||
"kind": {
|
||||
"Decrypted": {
|
||||
"encryption_info": {
|
||||
"algorithm_info": {
|
||||
"MegolmV1AesSha2": {
|
||||
"curve25519_key": "xxx",
|
||||
"sender_claimed_keys": {
|
||||
"curve25519": "qzdW3F5IMPFl0HQgz5w/L5Oi/npKUFn8Um84acIHfPY",
|
||||
"ed25519": "I3YsPwqMZQXHkSQbjFNEs7b529uac2xBpI83eN3LUXo"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sender": "@sender:example.com",
|
||||
"sender_device": "ABCDEFGHIJ",
|
||||
"verification_state": "Verified"
|
||||
},
|
||||
"event": {
|
||||
"content": {
|
||||
"body": "secret",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": "$xxxxx:example.org",
|
||||
"origin_server_ts": 2189,
|
||||
"room_id": "!someroom:example.com",
|
||||
"sender": "@carl:example.com",
|
||||
"type": "m.room.message"
|
||||
},
|
||||
"unsigned_encryption_info": {
|
||||
"RelationsThreadLatestEvent": {
|
||||
"UnableToDecrypt": {
|
||||
"reason": {
|
||||
"MissingMegolmSession": {
|
||||
"withheld_code": "m.unverified"
|
||||
}
|
||||
},
|
||||
"session_id": "xyz"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
source: crates/matrix-sdk-common/src/deserialized_responses.rs
|
||||
expression: "serde_json::to_value(&level).unwrap()"
|
||||
---
|
||||
"UnsignedDevice"
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
source: crates/matrix-sdk-common/src/deserialized_responses.rs
|
||||
expression: "serde_json::to_value(&level).unwrap()"
|
||||
---
|
||||
{
|
||||
"None": "InsecureSource"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
source: crates/matrix-sdk-common/src/deserialized_responses.rs
|
||||
expression: "serde_json::to_value(&level).unwrap()"
|
||||
---
|
||||
{
|
||||
"None": "MissingDevice"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
source: crates/matrix-sdk-common/src/deserialized_responses.rs
|
||||
expression: "serde_json::to_value(&level).unwrap()"
|
||||
---
|
||||
"UnverifiedIdentity"
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
source: crates/matrix-sdk-common/src/deserialized_responses.rs
|
||||
expression: "serde_json::to_value(&level).unwrap()"
|
||||
---
|
||||
"VerificationViolation"
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
source: crates/matrix-sdk-common/src/deserialized_responses.rs
|
||||
expression: "serde_json::to_value(&state).unwrap()"
|
||||
---
|
||||
{
|
||||
"Unverified": "VerificationViolation"
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
source: crates/matrix-sdk-common/src/deserialized_responses.rs
|
||||
expression: "serde_json::to_value(&state).unwrap()"
|
||||
---
|
||||
{
|
||||
"Unverified": {
|
||||
"None": "InsecureSource"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
source: crates/matrix-sdk-common/src/deserialized_responses.rs
|
||||
expression: "serde_json::to_value(&state).unwrap()"
|
||||
---
|
||||
{
|
||||
"Unverified": {
|
||||
"None": "MissingDevice"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
source: crates/matrix-sdk-common/src/deserialized_responses.rs
|
||||
expression: "serde_json::to_value(&state).unwrap()"
|
||||
---
|
||||
"Verified"
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
source: crates/matrix-sdk-common/src/deserialized_responses.rs
|
||||
expression: "serde_json::to_value(&state).unwrap()"
|
||||
---
|
||||
{
|
||||
"Unverified": "UnsignedDevice"
|
||||
}
|
||||
Reference in New Issue
Block a user