From 4c5ef036753fd16596e7ad3523c9cde2b4562719 Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Fri, 29 Nov 2024 13:39:35 +0000 Subject: [PATCH 1/3] task(backup_tests): Use helper functions to shorten exists_on_server tests --- .../matrix-sdk/src/encryption/backups/mod.rs | 110 ++++++++++-------- 1 file changed, 63 insertions(+), 47 deletions(-) diff --git a/crates/matrix-sdk/src/encryption/backups/mod.rs b/crates/matrix-sdk/src/encryption/backups/mod.rs index 437c6d8746c..4d017aa46a3 100644 --- a/crates/matrix-sdk/src/encryption/backups/mod.rs +++ b/crates/matrix-sdk/src/encryption/backups/mod.rs @@ -1010,7 +1010,7 @@ mod test { use serde_json::json; use wiremock::{ matchers::{header, method, path}, - Mock, MockServer, ResponseTemplate, + Mock, MockGuard, MockServer, ResponseTemplate, }; use super::*; @@ -1124,22 +1124,7 @@ mod test { let client = logged_in_client(Some(server.uri())).await; { - let _scope = Mock::given(method("GET")) - .and(path("_matrix/client/r0/room_keys/version")) - .and(header("authorization", "Bearer 1234")) - .respond_with(ResponseTemplate::new(200).set_body_json(json!({ - "algorithm": "m.megolm_backup.v1.curve25519-aes-sha2", - "auth_data": { - "public_key": "abcdefg", - "signatures": {}, - }, - "count": 42, - "etag": "anopaquestring", - "version": "1", - }))) - .expect(1) - .mount_as_scoped(&server) - .await; + let _scope = mock_backup_exists(&server).await; let exists = client .encryption() @@ -1148,20 +1133,11 @@ mod test { .await .expect("We should be able to check if backups exist on the server"); - assert!(exists, "We should deduce that a backup exist on the server"); + assert!(exists, "We should deduce that a backup exists on the server"); } { - let _scope = Mock::given(method("GET")) - .and(path("_matrix/client/r0/room_keys/version")) - .and(header("authorization", "Bearer 1234")) - .respond_with(ResponseTemplate::new(404).set_body_json(json!({ - "errcode": "M_NOT_FOUND", - "error": "No current backup version" - }))) - .expect(1) - .mount_as_scoped(&server) - .await; + let _scope = mock_backup_none(&server).await; let exists = client .encryption() @@ -1170,21 +1146,11 @@ mod test { .await .expect("We should be able to check if backups exist on the server"); - assert!(!exists, "We should deduce that no backup exist on the server"); + assert!(!exists, "We should deduce that no backup exists on the server"); } { - let _scope = Mock::given(method("GET")) - .and(path("_matrix/client/r0/room_keys/version")) - .and(header("authorization", "Bearer 1234")) - .respond_with(ResponseTemplate::new(429).set_body_json(json!({ - "errcode": "M_LIMIT_EXCEEDED", - "error": "Too many requests", - "retry_after_ms": 2000 - }))) - .expect(1) - .mount_as_scoped(&server) - .await; + let _scope = mock_backup_too_many_requests(&server).await; client.encryption().backups().exists_on_server().await.expect_err( "If the /version endpoint returns a non 404 error we should throw an error", @@ -1192,13 +1158,7 @@ mod test { } { - let _scope = Mock::given(method("GET")) - .and(path("_matrix/client/r0/room_keys/version")) - .and(header("authorization", "Bearer 1234")) - .respond_with(ResponseTemplate::new(404)) - .expect(1) - .mount_as_scoped(&server) - .await; + let _scope = mock_backup_404(&server); client.encryption().backups().exists_on_server().await.expect_err( "If the /version endpoint returns a non-Matrix 404 error we should throw an error", @@ -1282,4 +1242,60 @@ mod test { server.verify().await; } + + async fn mock_backup_exists(server: &MockServer) -> MockGuard { + Mock::given(method("GET")) + .and(path("_matrix/client/r0/room_keys/version")) + .and(header("authorization", "Bearer 1234")) + .respond_with(ResponseTemplate::new(200).set_body_json(json!({ + "algorithm": "m.megolm_backup.v1.curve25519-aes-sha2", + "auth_data": { + "public_key": "abcdefg", + "signatures": {}, + }, + "count": 42, + "etag": "anopaquestring", + "version": "1", + }))) + .expect(1) + .mount_as_scoped(server) + .await + } + + async fn mock_backup_none(server: &MockServer) -> MockGuard { + Mock::given(method("GET")) + .and(path("_matrix/client/r0/room_keys/version")) + .and(header("authorization", "Bearer 1234")) + .respond_with(ResponseTemplate::new(404).set_body_json(json!({ + "errcode": "M_NOT_FOUND", + "error": "No current backup version" + }))) + .expect(1) + .mount_as_scoped(server) + .await + } + + async fn mock_backup_too_many_requests(server: &MockServer) -> MockGuard { + Mock::given(method("GET")) + .and(path("_matrix/client/r0/room_keys/version")) + .and(header("authorization", "Bearer 1234")) + .respond_with(ResponseTemplate::new(429).set_body_json(json!({ + "errcode": "M_LIMIT_EXCEEDED", + "error": "Too many requests", + "retry_after_ms": 2000 + }))) + .expect(1) + .mount_as_scoped(server) + .await + } + + async fn mock_backup_404(server: &MockServer) -> MockGuard { + Mock::given(method("GET")) + .and(path("_matrix/client/r0/room_keys/version")) + .and(header("authorization", "Bearer 1234")) + .respond_with(ResponseTemplate::new(404)) + .expect(1) + .mount_as_scoped(server) + .await + } } From 5d3eaa9863e6d3973fe2e4b7f54fa8a8ed18c03a Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Fri, 29 Nov 2024 13:45:59 +0000 Subject: [PATCH 2/3] task(backup_tests): Split exists_on_server test into separate tests --- .../matrix-sdk/src/encryption/backups/mod.rs | 54 +++++++++++-------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/crates/matrix-sdk/src/encryption/backups/mod.rs b/crates/matrix-sdk/src/encryption/backups/mod.rs index 4d017aa46a3..bf64e580b42 100644 --- a/crates/matrix-sdk/src/encryption/backups/mod.rs +++ b/crates/matrix-sdk/src/encryption/backups/mod.rs @@ -1119,35 +1119,47 @@ mod test { } #[async_test] - async fn test_exists_on_server() { + async fn test_when_a_backup_exists_then_exists_on_server_returns_true() { let server = MockServer::start().await; let client = logged_in_client(Some(server.uri())).await; - { - let _scope = mock_backup_exists(&server).await; + let _scope = mock_backup_exists(&server).await; - let exists = client - .encryption() - .backups() - .exists_on_server() - .await - .expect("We should be able to check if backups exist on the server"); + let exists = client + .encryption() + .backups() + .exists_on_server() + .await + .expect("We should be able to check if backups exist on the server"); - assert!(exists, "We should deduce that a backup exists on the server"); - } + assert!(exists, "We should deduce that a backup exists on the server"); - { - let _scope = mock_backup_none(&server).await; + server.verify().await; + } - let exists = client - .encryption() - .backups() - .exists_on_server() - .await - .expect("We should be able to check if backups exist on the server"); + #[async_test] + async fn test_when_no_backup_exists_then_exists_on_server_returns_false() { + let server = MockServer::start().await; + let client = logged_in_client(Some(server.uri())).await; - assert!(!exists, "We should deduce that no backup exists on the server"); - } + let _scope = mock_backup_none(&server).await; + + let exists = client + .encryption() + .backups() + .exists_on_server() + .await + .expect("We should be able to check if backups exist on the server"); + + assert!(!exists, "We should deduce that no backup exists on the server"); + + server.verify().await; + } + + #[async_test] + async fn test_when_server_returns_an_error_then_exists_on_server_returns_an_error() { + let server = MockServer::start().await; + let client = logged_in_client(Some(server.uri())).await; { let _scope = mock_backup_too_many_requests(&server).await; From 944a1bab9affc84fbd5f1ac3ed0c2aa430569770 Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Tue, 3 Dec 2024 13:33:32 +0000 Subject: [PATCH 3/3] task(backup_tests): Move mock helpers into MatrixMockServer --- .../matrix-sdk/src/encryption/backups/mod.rs | 88 +++---------------- crates/matrix-sdk/src/test_utils/mocks.rs | 75 ++++++++++++++++ 2 files changed, 89 insertions(+), 74 deletions(-) diff --git a/crates/matrix-sdk/src/encryption/backups/mod.rs b/crates/matrix-sdk/src/encryption/backups/mod.rs index bf64e580b42..d0d0ad43e59 100644 --- a/crates/matrix-sdk/src/encryption/backups/mod.rs +++ b/crates/matrix-sdk/src/encryption/backups/mod.rs @@ -1010,11 +1010,11 @@ mod test { use serde_json::json; use wiremock::{ matchers::{header, method, path}, - Mock, MockGuard, MockServer, ResponseTemplate, + Mock, MockServer, ResponseTemplate, }; use super::*; - use crate::test_utils::logged_in_client; + use crate::test_utils::{logged_in_client, mocks::MatrixMockServer}; fn room_key() -> ExportedRoomKey { let json = json!({ @@ -1120,10 +1120,10 @@ mod test { #[async_test] async fn test_when_a_backup_exists_then_exists_on_server_returns_true() { - let server = MockServer::start().await; - let client = logged_in_client(Some(server.uri())).await; + let server = MatrixMockServer::new().await; + let client = server.client_builder().build().await; - let _scope = mock_backup_exists(&server).await; + server.mock_room_keys_version().exists().expect(1).mount().await; let exists = client .encryption() @@ -1133,16 +1133,14 @@ mod test { .expect("We should be able to check if backups exist on the server"); assert!(exists, "We should deduce that a backup exists on the server"); - - server.verify().await; } #[async_test] async fn test_when_no_backup_exists_then_exists_on_server_returns_false() { - let server = MockServer::start().await; - let client = logged_in_client(Some(server.uri())).await; + let server = MatrixMockServer::new().await; + let client = server.client_builder().build().await; - let _scope = mock_backup_none(&server).await; + server.mock_room_keys_version().none().expect(1).mount().await; let exists = client .encryption() @@ -1152,17 +1150,16 @@ mod test { .expect("We should be able to check if backups exist on the server"); assert!(!exists, "We should deduce that no backup exists on the server"); - - server.verify().await; } #[async_test] async fn test_when_server_returns_an_error_then_exists_on_server_returns_an_error() { - let server = MockServer::start().await; - let client = logged_in_client(Some(server.uri())).await; + let server = MatrixMockServer::new().await; + let client = server.client_builder().build().await; { - let _scope = mock_backup_too_many_requests(&server).await; + let _scope = + server.mock_room_keys_version().error429().expect(1).mount_as_scoped().await; client.encryption().backups().exists_on_server().await.expect_err( "If the /version endpoint returns a non 404 error we should throw an error", @@ -1170,14 +1167,13 @@ mod test { } { - let _scope = mock_backup_404(&server); + let _scope = + server.mock_room_keys_version().error404().expect(1).mount_as_scoped().await; client.encryption().backups().exists_on_server().await.expect_err( "If the /version endpoint returns a non-Matrix 404 error we should throw an error", ); } - - server.verify().await; } #[async_test] @@ -1254,60 +1250,4 @@ mod test { server.verify().await; } - - async fn mock_backup_exists(server: &MockServer) -> MockGuard { - Mock::given(method("GET")) - .and(path("_matrix/client/r0/room_keys/version")) - .and(header("authorization", "Bearer 1234")) - .respond_with(ResponseTemplate::new(200).set_body_json(json!({ - "algorithm": "m.megolm_backup.v1.curve25519-aes-sha2", - "auth_data": { - "public_key": "abcdefg", - "signatures": {}, - }, - "count": 42, - "etag": "anopaquestring", - "version": "1", - }))) - .expect(1) - .mount_as_scoped(server) - .await - } - - async fn mock_backup_none(server: &MockServer) -> MockGuard { - Mock::given(method("GET")) - .and(path("_matrix/client/r0/room_keys/version")) - .and(header("authorization", "Bearer 1234")) - .respond_with(ResponseTemplate::new(404).set_body_json(json!({ - "errcode": "M_NOT_FOUND", - "error": "No current backup version" - }))) - .expect(1) - .mount_as_scoped(server) - .await - } - - async fn mock_backup_too_many_requests(server: &MockServer) -> MockGuard { - Mock::given(method("GET")) - .and(path("_matrix/client/r0/room_keys/version")) - .and(header("authorization", "Bearer 1234")) - .respond_with(ResponseTemplate::new(429).set_body_json(json!({ - "errcode": "M_LIMIT_EXCEEDED", - "error": "Too many requests", - "retry_after_ms": 2000 - }))) - .expect(1) - .mount_as_scoped(server) - .await - } - - async fn mock_backup_404(server: &MockServer) -> MockGuard { - Mock::given(method("GET")) - .and(path("_matrix/client/r0/room_keys/version")) - .and(header("authorization", "Bearer 1234")) - .respond_with(ResponseTemplate::new(404)) - .expect(1) - .mount_as_scoped(server) - .await - } } diff --git a/crates/matrix-sdk/src/test_utils/mocks.rs b/crates/matrix-sdk/src/test_utils/mocks.rs index 6774102f227..46981c4b6c5 100644 --- a/crates/matrix-sdk/src/test_utils/mocks.rs +++ b/crates/matrix-sdk/src/test_utils/mocks.rs @@ -560,6 +560,36 @@ impl MatrixMockServer { let mock = Mock::given(method("POST")).and(path_regex(r"/_matrix/client/v3/publicRooms")); MockEndpoint { mock, server: &self.server, endpoint: PublicRoomsEndpoint } } + + /// Create a prebuilt mock for fetching information about key storage + /// backups. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "e2e-encryption")] + /// # { + /// # tokio_test::block_on(async { + /// use matrix_sdk::test_utils::mocks::MatrixMockServer; + /// + /// let mock_server = MatrixMockServer::new().await; + /// let client = mock_server.client_builder().build().await; + /// + /// mock_server.mock_room_keys_version().exists().expect(1).mount().await; + /// + /// let exists = + /// client.encryption().backups().exists_on_server().await.unwrap(); + /// + /// assert!(exists); + /// # }); + /// # } + /// ``` + pub fn mock_room_keys_version(&self) -> MockEndpoint<'_, RoomKeysVersionEndpoint> { + let mock = Mock::given(method("GET")) + .and(path_regex(r"_matrix/client/v3/room_keys/version")) + .and(header("authorization", "Bearer 1234")); + MockEndpoint { mock, server: &self.server, endpoint: RoomKeysVersionEndpoint } + } } /// Parameter to [`MatrixMockServer::sync_room`]. @@ -1503,3 +1533,48 @@ impl<'a> MockEndpoint<'a, PublicRoomsEndpoint> { MatrixMock { server: self.server, mock } } } + +/// A prebuilt mock for `room_keys/version`: storage ("backup") of room keys. +pub struct RoomKeysVersionEndpoint; + +impl<'a> MockEndpoint<'a, RoomKeysVersionEndpoint> { + /// Returns an endpoint that says there is a single room keys backup + pub fn exists(self) -> MatrixMock<'a> { + let mock = self.mock.respond_with(ResponseTemplate::new(200).set_body_json(json!({ + "algorithm": "m.megolm_backup.v1.curve25519-aes-sha2", + "auth_data": { + "public_key": "abcdefg", + "signatures": {}, + }, + "count": 42, + "etag": "anopaquestring", + "version": "1", + }))); + MatrixMock { server: self.server, mock } + } + + /// Returns an endpoint that says there is no room keys backup + pub fn none(self) -> MatrixMock<'a> { + let mock = self.mock.respond_with(ResponseTemplate::new(404).set_body_json(json!({ + "errcode": "M_NOT_FOUND", + "error": "No current backup version" + }))); + MatrixMock { server: self.server, mock } + } + + /// Returns an endpoint that 429 errors when we get it + pub fn error429(self) -> MatrixMock<'a> { + let mock = self.mock.respond_with(ResponseTemplate::new(429).set_body_json(json!({ + "errcode": "M_LIMIT_EXCEEDED", + "error": "Too many requests", + "retry_after_ms": 2000 + }))); + MatrixMock { server: self.server, mock } + } + + /// Returns an endpoint that 404 errors when we get it + pub fn error404(self) -> MatrixMock<'a> { + let mock = self.mock.respond_with(ResponseTemplate::new(404)); + MatrixMock { server: self.server, mock } + } +}