matrix_sdk/test_utils/
client.rs1use matrix_sdk_base::{SessionMeta, store::RoomLoadSettings};
18use matrix_sdk_test::{TestDevice, User};
19use ruma::{OwnedDeviceId, OwnedUserId, api::MatrixVersion};
20
21use crate::{
22 Client, ClientBuilder, SessionTokens, authentication::matrix::MatrixSession,
23 config::RequestConfig,
24};
25
26#[allow(missing_debug_implementations)]
28pub struct MockClientBuilder {
29 builder: ClientBuilder,
30 auth_state: AuthState,
31 server_versions: ServerVersions,
32}
33
34impl MockClientBuilder {
35 pub fn new(homeserver: Option<&str>) -> Self {
42 let homeserver = homeserver.unwrap_or("http://localhost");
43
44 let default_builder = Client::builder()
45 .homeserver_url(homeserver)
46 .request_config(RequestConfig::new().disable_retry());
47
48 Self {
49 builder: default_builder,
50 auth_state: AuthState::LoggedInWithMatrixAuth {
51 token: None,
52 user_id: None,
53 device_id: None,
54 },
55 server_versions: ServerVersions::Default,
56 }
57 }
58
59 pub fn no_server_versions(mut self) -> Self {
61 self.server_versions = ServerVersions::None;
62 self
63 }
64
65 pub fn server_versions(mut self, versions: Vec<MatrixVersion>) -> Self {
67 self.server_versions = ServerVersions::Custom(versions);
68 self
69 }
70
71 pub fn unlogged(mut self) -> Self {
75 self.auth_state = AuthState::None;
76 self
77 }
78
79 pub fn registered_with_oauth(mut self) -> Self {
81 self.auth_state = AuthState::RegisteredWithOAuth;
82 self
83 }
84
85 pub fn logged_in_with_oauth(mut self) -> Self {
87 self.auth_state = AuthState::LoggedInWithOAuth;
88 self
89 }
90
91 pub fn logged_in_with_token(
93 mut self,
94 token: String,
95 user_id: OwnedUserId,
96 device_id: OwnedDeviceId,
97 ) -> Self {
98 self.auth_state = AuthState::LoggedInWithMatrixAuth {
99 token: Some(token),
100 user_id: Some(user_id),
101 device_id: Some(device_id),
102 };
103 self
104 }
105
106 pub fn on_builder<F: FnOnce(ClientBuilder) -> ClientBuilder>(mut self, f: F) -> Self {
125 self.builder = f(self.builder);
126 self
127 }
128
129 pub async fn build(self) -> Client {
131 let mut builder = self.builder;
132
133 if let Some(versions) = self.server_versions.into_vec() {
134 builder = builder.server_versions(versions);
135 }
136
137 let client = builder.build().await.expect("building client failed");
138
139 self.auth_state.maybe_restore_client(&client).await;
140
141 client
142 }
143}
144
145enum AuthState {
148 None,
150 LoggedInWithMatrixAuth {
152 token: Option<String>,
153 user_id: Option<OwnedUserId>,
154 device_id: Option<OwnedDeviceId>,
155 },
156 RegisteredWithOAuth,
158 LoggedInWithOAuth,
160}
161
162impl AuthState {
163 async fn maybe_restore_client(self, client: &Client) {
166 match self {
167 AuthState::None => {}
168 AuthState::LoggedInWithMatrixAuth { token, user_id, device_id } => {
169 client
170 .matrix_auth()
171 .restore_session(
172 MatrixSession {
173 meta: SessionMeta {
174 user_id: user_id.unwrap_or_else(|| User::Default.into()),
175 device_id: device_id.unwrap_or_else(|| TestDevice::Default.into()),
176 },
177 tokens: SessionTokens {
178 access_token: token.unwrap_or_else(|| "1234".to_owned()),
179 refresh_token: None,
180 },
181 },
182 RoomLoadSettings::default(),
183 )
184 .await
185 .unwrap();
186 }
187 AuthState::RegisteredWithOAuth => {
188 client.oauth().restore_registered_client(oauth::mock_client_id());
189 }
190 AuthState::LoggedInWithOAuth => {
191 client
192 .oauth()
193 .restore_session(
194 oauth::mock_session(mock_session_tokens_with_refresh()),
195 RoomLoadSettings::default(),
196 )
197 .await
198 .unwrap();
199 }
200 }
201 }
202}
203
204enum ServerVersions {
206 Default,
208 None,
210 Custom(Vec<MatrixVersion>),
212}
213
214impl ServerVersions {
215 fn into_vec(self) -> Option<Vec<MatrixVersion>> {
219 match self {
220 Self::Default => Some(vec![MatrixVersion::V1_12]),
221 Self::None => None,
222 Self::Custom(versions) => Some(versions),
223 }
224 }
225}
226
227pub fn mock_session_meta() -> SessionMeta {
229 SessionMeta { user_id: User::Default.into(), device_id: TestDevice::Default.into() }
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 SessionTokens,
265 authentication::oauth::{
266 ClientId, OAuthSession, UserSession,
267 registration::{ApplicationType, ClientMetadata, Localized, OAuthGrantType},
268 },
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}