matrix_sdk/test_utils/
client.rs1use matrix_sdk_base::{store::RoomLoadSettings, SessionMeta};
18use ruma::{api::MatrixVersion, owned_device_id, owned_user_id, OwnedDeviceId, OwnedUserId};
19
20use crate::{
21 authentication::matrix::MatrixSession, config::RequestConfig, Client, ClientBuilder,
22 SessionTokens,
23};
24
25#[allow(missing_debug_implementations)]
27pub struct MockClientBuilder {
28 builder: ClientBuilder,
29 auth_state: AuthState,
30 server_versions: ServerVersions,
31}
32
33impl MockClientBuilder {
34 pub fn new(homeserver: Option<&str>) -> Self {
40 let homeserver = homeserver.unwrap_or("http://localhost");
41
42 let default_builder = Client::builder()
43 .homeserver_url(homeserver)
44 .request_config(RequestConfig::new().disable_retry());
45
46 Self {
47 builder: default_builder,
48 auth_state: AuthState::LoggedInWithMatrixAuth {
49 token: None,
50 user_id: None,
51 device_id: None,
52 },
53 server_versions: ServerVersions::Default,
54 }
55 }
56
57 pub fn no_server_versions(mut self) -> Self {
59 self.server_versions = ServerVersions::None;
60 self
61 }
62
63 pub fn server_versions(mut self, versions: Vec<MatrixVersion>) -> Self {
65 self.server_versions = ServerVersions::Custom(versions);
66 self
67 }
68
69 pub fn unlogged(mut self) -> Self {
73 self.auth_state = AuthState::None;
74 self
75 }
76
77 pub fn registered_with_oauth(mut self) -> Self {
79 self.auth_state = AuthState::RegisteredWithOAuth;
80 self
81 }
82
83 pub fn logged_in_with_oauth(mut self) -> Self {
85 self.auth_state = AuthState::LoggedInWithOAuth;
86 self
87 }
88
89 pub fn logged_in_with_token(
91 mut self,
92 token: String,
93 user_id: OwnedUserId,
94 device_id: OwnedDeviceId,
95 ) -> Self {
96 self.auth_state = AuthState::LoggedInWithMatrixAuth {
97 token: Some(token),
98 user_id: Some(user_id),
99 device_id: Some(device_id),
100 };
101 self
102 }
103
104 pub fn on_builder<F: FnOnce(ClientBuilder) -> ClientBuilder>(mut self, f: F) -> Self {
122 self.builder = f(self.builder);
123 self
124 }
125
126 pub async fn build(self) -> Client {
128 let mut builder = self.builder;
129
130 if let Some(versions) = self.server_versions.into_vec() {
131 builder = builder.server_versions(versions);
132 }
133
134 let client = builder.build().await.expect("building client failed");
135
136 self.auth_state.maybe_restore_client(&client).await;
137
138 client
139 }
140}
141
142enum AuthState {
145 None,
147 LoggedInWithMatrixAuth {
149 token: Option<String>,
150 user_id: Option<OwnedUserId>,
151 device_id: Option<OwnedDeviceId>,
152 },
153 RegisteredWithOAuth,
155 LoggedInWithOAuth,
157}
158
159impl AuthState {
160 async fn maybe_restore_client(self, client: &Client) {
163 match self {
164 AuthState::None => {}
165 AuthState::LoggedInWithMatrixAuth { token, user_id, device_id } => {
166 client
167 .matrix_auth()
168 .restore_session(
169 MatrixSession {
170 meta: SessionMeta {
171 user_id: user_id.unwrap_or(owned_user_id!("@example:localhost")),
172 device_id: device_id.unwrap_or(owned_device_id!("DEVICEID")),
173 },
174 tokens: SessionTokens {
175 access_token: token.unwrap_or("1234".to_owned()).to_owned(),
176 refresh_token: None,
177 },
178 },
179 RoomLoadSettings::default(),
180 )
181 .await
182 .unwrap();
183 }
184 AuthState::RegisteredWithOAuth => {
185 client.oauth().restore_registered_client(oauth::mock_client_id());
186 }
187 AuthState::LoggedInWithOAuth => {
188 client
189 .oauth()
190 .restore_session(
191 oauth::mock_session(mock_session_tokens_with_refresh()),
192 RoomLoadSettings::default(),
193 )
194 .await
195 .unwrap();
196 }
197 }
198 }
199}
200
201enum ServerVersions {
203 Default,
205 None,
207 Custom(Vec<MatrixVersion>),
209}
210
211impl ServerVersions {
212 fn into_vec(self) -> Option<Vec<MatrixVersion>> {
216 match self {
217 Self::Default => Some(vec![MatrixVersion::V1_12]),
218 Self::None => None,
219 Self::Custom(versions) => Some(versions),
220 }
221 }
222}
223
224pub fn mock_session_meta() -> SessionMeta {
226 SessionMeta {
227 user_id: owned_user_id!("@example:localhost"),
228 device_id: owned_device_id!("DEVICEID"),
229 }
230}
231
232pub fn mock_session_tokens() -> SessionTokens {
235 SessionTokens { access_token: "1234".to_owned(), refresh_token: None }
236}
237
238pub fn mock_session_tokens_with_refresh() -> SessionTokens {
241 SessionTokens { access_token: "1234".to_owned(), refresh_token: Some("ZYXWV".to_owned()) }
242}
243
244pub fn mock_prev_session_tokens_with_refresh() -> SessionTokens {
247 SessionTokens {
248 access_token: "prev-access-token".to_owned(),
249 refresh_token: Some("prev-refresh-token".to_owned()),
250 }
251}
252
253pub fn mock_matrix_session() -> MatrixSession {
255 MatrixSession { meta: mock_session_meta(), tokens: mock_session_tokens() }
256}
257
258pub mod oauth {
260 use ruma::serde::Raw;
261 use url::Url;
262
263 use crate::{
264 authentication::oauth::{
265 registration::{ApplicationType, ClientMetadata, Localized, OAuthGrantType},
266 ClientId, OAuthSession, UserSession,
267 },
268 SessionTokens,
269 };
270
271 pub fn mock_client_id() -> ClientId {
273 ClientId::new("test_client_id".to_owned())
274 }
275
276 pub fn mock_redirect_uri() -> Url {
278 Url::parse("http://127.0.0.1/").expect("redirect URI should be valid")
279 }
280
281 pub fn mock_client_metadata() -> Raw<ClientMetadata> {
284 let client_uri = Url::parse("https://github.com/matrix-org/matrix-rust-sdk")
285 .expect("client URI should be valid");
286
287 let mut metadata = ClientMetadata::new(
288 ApplicationType::Native,
289 vec![
290 OAuthGrantType::AuthorizationCode { redirect_uris: vec![mock_redirect_uri()] },
291 OAuthGrantType::DeviceCode,
292 ],
293 Localized::new(client_uri, None),
294 );
295 metadata.client_name = Some(Localized::new("matrix-rust-sdk-test".to_owned(), None));
296
297 Raw::new(&metadata).expect("client metadata should serialize successfully")
298 }
299
300 pub fn mock_session(tokens: SessionTokens) -> OAuthSession {
302 OAuthSession {
303 client_id: mock_client_id(),
304 user: UserSession { meta: super::mock_session_meta(), tokens },
305 }
306 }
307}