Skip to content

Commit 4468c36

Browse files
BillCarsonFrpoljar
authored andcommitted
review: extend existing MatrixMockServer instead of creating another
1 parent 25841c7 commit 4468c36

File tree

6 files changed

+179
-189
lines changed

6 files changed

+179
-189
lines changed

crates/matrix-sdk/src/test_utils/client.rs

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use matrix_sdk_base::{
1818
store::{RoomLoadSettings, StoreConfig},
1919
SessionMeta,
2020
};
21-
use ruma::{api::MatrixVersion, owned_device_id, owned_user_id};
21+
use ruma::{api::MatrixVersion, owned_device_id, owned_user_id, OwnedDeviceId, OwnedUserId};
2222

2323
use crate::{
2424
authentication::matrix::MatrixSession, config::RequestConfig, Client, ClientBuilder,
@@ -42,7 +42,14 @@ impl MockClientBuilder {
4242
.server_versions([MatrixVersion::V1_12])
4343
.request_config(RequestConfig::new().disable_retry());
4444

45-
Self { builder: default_builder, auth_state: AuthState::LoggedInWithMatrixAuth }
45+
Self {
46+
builder: default_builder,
47+
auth_state: AuthState::LoggedInWithMatrixAuth {
48+
token: None,
49+
user_id: None,
50+
device_id: None,
51+
},
52+
}
4653
}
4754

4855
/// Doesn't log-in a user.
@@ -65,6 +72,21 @@ impl MockClientBuilder {
6572
self
6673
}
6774

75+
/// The user is already logged in with the Matrix Auth.
76+
pub fn logged_in_with_token(
77+
mut self,
78+
token: String,
79+
user_id: OwnedUserId,
80+
device_id: OwnedDeviceId,
81+
) -> Self {
82+
self.auth_state = AuthState::LoggedInWithMatrixAuth {
83+
token: Some(token),
84+
user_id: Some(user_id),
85+
device_id: Some(device_id),
86+
};
87+
self
88+
}
89+
6890
/// Provides another [`StoreConfig`] for the underlying [`ClientBuilder`].
6991
pub fn store_config(mut self, store_config: StoreConfig) -> Self {
7092
self.builder = self.builder.store_config(store_config);
@@ -100,7 +122,11 @@ enum AuthState {
100122
/// The client is not logged in.
101123
None,
102124
/// The client is logged in with the native Matrix API.
103-
LoggedInWithMatrixAuth,
125+
LoggedInWithMatrixAuth {
126+
token: Option<String>,
127+
user_id: Option<OwnedUserId>,
128+
device_id: Option<OwnedDeviceId>,
129+
},
104130
/// The client is registered with the OAuth 2.0 API.
105131
RegisteredWithOAuth,
106132
/// The client is logged in with the OAuth 2.0 API.
@@ -113,10 +139,22 @@ impl AuthState {
113139
async fn maybe_restore_client(self, client: &Client) {
114140
match self {
115141
AuthState::None => {}
116-
AuthState::LoggedInWithMatrixAuth => {
142+
AuthState::LoggedInWithMatrixAuth { token, user_id, device_id } => {
117143
client
118144
.matrix_auth()
119-
.restore_session(mock_matrix_session(), RoomLoadSettings::default())
145+
.restore_session(
146+
MatrixSession {
147+
meta: SessionMeta {
148+
user_id: user_id.unwrap_or(owned_user_id!("@example:localhost")),
149+
device_id: device_id.unwrap_or(owned_device_id!("DEVICEID")),
150+
},
151+
tokens: SessionTokens {
152+
access_token: token.unwrap_or("1234".to_owned()).to_owned(),
153+
refresh_token: None,
154+
},
155+
},
156+
RoomLoadSettings::default(),
157+
)
120158
.await
121159
.unwrap();
122160
}

crates/matrix-sdk/src/test_utils/mocks/encryption.rs

Lines changed: 54 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -17,44 +17,32 @@
1717
//! tests.
1818
use std::{
1919
collections::BTreeMap,
20-
sync::{
21-
atomic::{AtomicU32, Ordering},
22-
Arc, Mutex,
23-
},
20+
sync::{atomic::Ordering, Arc, Mutex},
2421
};
2522

26-
use matrix_sdk_base::SessionMeta;
27-
use matrix_sdk_test::SyncResponseBuilder;
2823
use ruma::{
29-
api::{client::keys::upload_signatures::v3::SignedKeys, MatrixVersion},
24+
api::client::keys::upload_signatures::v3::SignedKeys,
3025
encryption::{CrossSigningKey, DeviceKeys, OneTimeKey},
3126
owned_device_id, owned_user_id,
3227
serde::Raw,
3328
CrossSigningKeyId, DeviceId, OneTimeKeyAlgorithm, OwnedDeviceId, OwnedOneTimeKeyId,
3429
OwnedUserId, UserId,
3530
};
36-
use serde::Serialize;
3731
use serde_json::json;
3832
use wiremock::{
39-
matchers::{method, path, query_param, query_param_is_missing},
40-
Mock, MockGuard, MockServer, Request, ResponseTemplate,
33+
matchers::{method, path_regex},
34+
Mock, Request, ResponseTemplate,
4135
};
4236

43-
use crate::{authentication::matrix::MatrixSession, config::RequestConfig, Client, SessionTokens};
44-
45-
#[derive(Debug, Default)]
46-
struct Keys {
47-
device: BTreeMap<OwnedUserId, BTreeMap<String, Raw<DeviceKeys>>>,
48-
master: BTreeMap<OwnedUserId, Raw<CrossSigningKey>>,
49-
self_signing: BTreeMap<OwnedUserId, Raw<CrossSigningKey>>,
50-
user_signing: BTreeMap<OwnedUserId, Raw<CrossSigningKey>>,
51-
one_time_keys: BTreeMap<
52-
OwnedUserId,
53-
BTreeMap<OwnedDeviceId, BTreeMap<OwnedOneTimeKeyId, Raw<OneTimeKey>>>,
54-
>,
55-
}
37+
use crate::{
38+
test_utils::{
39+
client::MockClientBuilder,
40+
mocks::{Keys, MatrixMockServer},
41+
},
42+
Client,
43+
};
5644

57-
/// A [`wiremock`] [`MockServer`] along with useful methods to help mocking
45+
/// Extends the `MatrixMockServer` with useful methods to help mocking
5846
/// matrix crypto API and perform integration test with encryption.
5947
///
6048
/// It implements mock endpoints for the `keys/upload`, will store the uploaded
@@ -65,66 +53,26 @@ struct Keys {
6553
/// client running out of otks. More can be added if needed later.
6654
///
6755
/// It works like this:
68-
/// * Start by creating the mock server like this [`MatrixKeysMockServer::new`].
69-
/// It will setup the mocks
70-
/// * Create your test client using [`MatrixKeysMockServer::create_client`],
71-
/// this is important as it will set up an access token that will allow to
72-
/// know what client is doing what request.
73-
///
74-
/// # Examples
75-
///
76-
/// ```
77-
/// # tokio_test::block_on(async {
78-
/// use matrix_sdk::{
79-
/// ruma::{device_id, user_id},
80-
/// test_utils::mocks::encryption::MatrixKeysMockServer,
81-
/// };
82-
/// let mock_server = MatrixKeysMockServer::new().await;
83-
///
84-
/// let (alice, bob) = mock_server.set_up_alice_and_bob_for_encryption().await;
56+
/// * Start by creating the mock server like this [`MatrixMockServer::new`].
57+
/// * Then mock the crypto API endpoints
58+
/// [`MatrixMockServer::mock_crypto_endpoints_preset`].
59+
/// * Create your test client using
60+
/// [`MatrixMockServer::client_builder_for_crypto_end_to_end`], this is
61+
/// important as it will set up an access token that will allow to know what
62+
/// client is doing what request.
8563
///
86-
/// let alice_bob_device = alice
87-
/// .encryption()
88-
/// .get_device(bob.user_id().unwrap(), bob.device_id().unwrap())
89-
/// .await
90-
/// .unwrap()
91-
/// .expect("alice sees bob's device");
92-
///
93-
/// # anyhow::Ok(()) });
94-
/// ```
95-
pub struct MatrixKeysMockServer {
96-
/// The underlying [`wiremock`] [`MockServer`]
97-
pub server: MockServer,
98-
keys: Arc<Mutex<Keys>>,
99-
token_to_user_id_map: Arc<Mutex<BTreeMap<String, OwnedUserId>>>,
100-
token_counter: AtomicU32,
101-
}
102-
103-
impl MatrixKeysMockServer {
104-
/// Creates a new `MatrixKeysMockServer` and mocks the crypto API end-points
105-
pub async fn new() -> Self {
106-
let server = MockServer::start().await;
107-
let keys: Arc<Mutex<Keys>> = Default::default();
108-
let mock_keys_server = Self {
109-
server,
110-
keys,
111-
token_to_user_id_map: Default::default(),
112-
token_counter: Default::default(),
113-
};
114-
mock_keys_server.mock_endpoints().await;
115-
mock_keys_server
116-
}
117-
118-
/// Creates a `Client` that will use this mock server.
119-
pub async fn create_client(&self, user_id: &UserId, device_id: &DeviceId) -> Client {
120-
let client = Client::builder()
121-
.homeserver_url(self.server.uri())
122-
.server_versions([MatrixVersion::V1_0])
123-
.request_config(RequestConfig::new().disable_retry())
124-
.build()
125-
.await
126-
.unwrap();
127-
64+
/// The [`MatrixMockServer::set_up_alice_and_bob_for_encryption`] will set up
65+
/// two olm machines aware of each other and ready to communicate.
66+
impl MatrixMockServer {
67+
/// Creates a new [`MockClientBuilder`] configured to use this server and
68+
/// suitable for usage of the crypto API end points.
69+
/// Will create a specific access token and some mapping to the associated
70+
/// user_id.
71+
pub fn client_builder_for_crypto_end_to_end(
72+
&self,
73+
user_id: &UserId,
74+
device_id: &DeviceId,
75+
) -> MockClientBuilder {
12876
// Create an access token and store the token to user_id mapping
12977
let next = self.token_counter.fetch_add(1, Ordering::Relaxed);
13078
let access_token = format!("TOKEN_{}", next);
@@ -135,15 +83,11 @@ impl MatrixKeysMockServer {
13583
mappings.insert(auth_string, user_id.to_owned());
13684
}
13785

138-
client
139-
.restore_session(MatrixSession {
140-
meta: SessionMeta { user_id: user_id.to_owned(), device_id: device_id.to_owned() },
141-
tokens: SessionTokens { access_token, refresh_token: None },
142-
})
143-
.await
144-
.unwrap();
145-
146-
client
86+
MockClientBuilder::new(self.server.uri()).logged_in_with_token(
87+
access_token,
88+
user_id.to_owned(),
89+
device_id.to_owned(),
90+
)
14791
}
14892

14993
/// Makes the server forget about all the one-time-keys for that device.
@@ -159,11 +103,15 @@ impl MatrixKeysMockServer {
159103
let alice_user_id = owned_user_id!("@alice:example.org");
160104
let alice_device_id = owned_device_id!("4L1C3");
161105

162-
let alice = self.create_client(&alice_user_id, &alice_device_id).await;
106+
let alice = self
107+
.client_builder_for_crypto_end_to_end(&alice_user_id, &alice_device_id)
108+
.build()
109+
.await;
163110

164111
let bob_user_id = owned_user_id!("@bob:example.org");
165112
let bob_device_id = owned_device_id!("B0B0B0B0B");
166-
let bob = self.create_client(&bob_user_id, &bob_device_id).await;
113+
let bob =
114+
self.client_builder_for_crypto_end_to_end(&bob_user_id, &bob_device_id).build().await;
167115

168116
// Have Alice track Bob, so she queries his keys later.
169117
{
@@ -174,67 +122,49 @@ impl MatrixKeysMockServer {
174122

175123
// Have Alice and Bob upload their signed device keys.
176124
{
177-
let mut sync_response_builder = SyncResponseBuilder::new();
178-
let response_body = sync_response_builder.build_json_sync_response();
179-
let _scope = mock_sync_scoped(&self.server, response_body, None).await;
180-
181-
alice
182-
.sync_once(Default::default())
183-
.await
184-
.expect("We should be able to sync with Alice so we upload the device keys");
185-
bob.sync_once(Default::default()).await.unwrap();
125+
self.mock_sync().ok_and_run(&alice, |_x| {}).await;
126+
self.mock_sync().ok_and_run(&bob, |_x| {}).await;
186127
}
187128

188129
// Run a sync so we do send outgoing requests, including the /keys/query for
189130
// getting bob's identity.
190-
let mut sync_response_builder = SyncResponseBuilder::new();
191-
192-
{
193-
let _scope = mock_sync_scoped(
194-
&self.server,
195-
sync_response_builder.build_json_sync_response(),
196-
None,
197-
)
198-
.await;
199-
alice
200-
.sync_once(Default::default())
201-
.await
202-
.expect("We should be able to sync so we get theinitial set of devices");
203-
}
131+
self.mock_sync().ok_and_run(&alice, |_x| {}).await;
204132

205133
(alice, bob)
206134
}
207135

208-
async fn mock_endpoints(&self) {
136+
/// Mock up the various crypto API so that it can serve back keys when
137+
/// needed
138+
pub async fn mock_crypto_endpoints_preset(&self) {
209139
let keys = &self.keys;
210140
let token_map = &self.token_to_user_id_map;
211141

212142
Mock::given(method("POST"))
213-
.and(path("/_matrix/client/r0/keys/query"))
143+
.and(path_regex(r"^/_matrix/client/.*/keys/query"))
214144
.respond_with(mock_keys_query(keys.clone()))
215145
.mount(&self.server)
216146
.await;
217147

218148
Mock::given(method("POST"))
219-
.and(path("/_matrix/client/r0/keys/upload"))
149+
.and(path_regex(r"^/_matrix/client/.*/keys/upload"))
220150
.respond_with(mock_keys_upload(keys.clone(), token_map.clone()))
221151
.mount(&self.server)
222152
.await;
223153

224154
Mock::given(method("POST"))
225-
.and(path("/_matrix/client/unstable/keys/device_signing/upload"))
155+
.and(path_regex(r"^/_matrix/client/.*/keys/device_signing/upload"))
226156
.respond_with(mock_keys_device_signing_upload(keys.clone()))
227157
.mount(&self.server)
228158
.await;
229159

230160
Mock::given(method("POST"))
231-
.and(path("/_matrix/client/unstable/keys/signatures/upload"))
161+
.and(path_regex(r"^/_matrix/client/.*/keys/signatures/upload"))
232162
.respond_with(mock_keys_signature_upload(keys.clone()))
233163
.mount(&self.server)
234164
.await;
235165

236166
Mock::given(method("POST"))
237-
.and(path("/_matrix/client/r0/keys/claim"))
167+
.and(path_regex(r"^/_matrix/client/.*/keys/claim"))
238168
.respond_with(mock_keys_claimed_request(keys.clone()))
239169
.mount(&self.server)
240170
.await;
@@ -310,7 +240,7 @@ fn mock_keys_upload(
310240
let tokens = token_to_user_id_map.lock().unwrap();
311241
// Get the user
312242
let user_id = tokens.get(bearer_token)
313-
.expect("Expect this token to be known, ensure you use `MatrixKeysMockServer::createClient`")
243+
.expect("Expect this token to be known, ensure you use `MatrixKeysServer::client_builder_for_crypto_end_to_end`")
314244
.to_owned();
315245

316246
if let Some(new_device_keys) = params.device_keys {
@@ -556,25 +486,3 @@ fn mock_keys_claimed_request(keys: Arc<Mutex<Keys>>) -> impl Fn(&Request) -> Res
556486
}))
557487
}
558488
}
559-
560-
/// Mount a Mock on the given server to handle the `GET /sync` endpoint with
561-
/// an optional `since` param that returns a 200 status code with the given
562-
/// response body.
563-
async fn mock_sync_scoped(
564-
server: &MockServer,
565-
response_body: impl Serialize,
566-
since: Option<String>,
567-
) -> MockGuard {
568-
let mut builder = Mock::given(method("GET")).and(path("/_matrix/client/r0/sync"));
569-
570-
if let Some(since) = since {
571-
builder = builder.and(query_param("since", since));
572-
} else {
573-
builder = builder.and(query_param_is_missing("since"));
574-
}
575-
576-
builder
577-
.respond_with(ResponseTemplate::new(200).set_body_json(response_body))
578-
.mount_as_scoped(server)
579-
.await
580-
}

0 commit comments

Comments
 (0)