diff --git a/services/commtest/tests/identity_device_list_tests.rs b/services/commtest/tests/identity_device_list_tests.rs --- a/services/commtest/tests/identity_device_list_tests.rs +++ b/services/commtest/tests/identity_device_list_tests.rs @@ -5,10 +5,13 @@ PLACEHOLDER_CODE_VERSION, }; use commtest::service_addr; +use grpc_clients::identity::authenticated::ChainedInterceptedAuthClient; use grpc_clients::identity::get_auth_client; +use grpc_clients::identity::protos::auth::UpdateDeviceListRequest; use grpc_clients::identity::protos::authenticated::GetDeviceListRequest; use grpc_clients::identity::DeviceType; use serde::Deserialize; +use serde_json::{from_str, json}; // 1. register user with android device // 2. register a web device @@ -20,7 +23,7 @@ // - [web] // - [ios, web] - mobile should be first #[tokio::test] -async fn test_device_list_updates() { +async fn test_device_list_rotation() { use commtest::identity::olm_account_infos::{ DEFAULT_CLIENT_KEYS as DEVICE_KEYS_ANDROID, MOCK_CLIENT_KEYS_1 as DEVICE_KEYS_WEB, @@ -66,29 +69,12 @@ .await; // Get device list updates for the user - let request = GetDeviceListRequest { - user_id, - since_timestamp: None, - }; - let response = auth_client - .get_device_list_for_user(request) - .await - .expect("Get device list request failed") - .into_inner(); - - let device_lists_response: Vec> = response - .device_list_updates - .into_iter() - .map(|update| { - let update: DeviceListUpdate = serde_json::from_str(&update) - .expect("Failed to parse device list update"); - let device_list: RawDeviceList = update - .raw_device_list - .parse() - .expect("Failed to parse raw device list"); - device_list.devices - }) - .collect(); + let device_lists_response: Vec> = + get_device_list_history(&mut auth_client, &user_id) + .await + .into_iter() + .map(|device_list| device_list.devices) + .collect(); let expected_device_list: Vec> = vec![ vec![android_device_id.into()], @@ -100,6 +86,64 @@ assert_eq!(device_lists_response, expected_device_list); } +#[tokio::test] +async fn test_update_device_list_rpc() { + // Register user with primary device + let primary_device = register_user_device(None, None).await; + let mut auth_client = get_auth_client( + &service_addr::IDENTITY_GRPC.to_string(), + primary_device.user_id.clone(), + primary_device.device_id, + primary_device.access_token, + PLACEHOLDER_CODE_VERSION, + DEVICE_TYPE.to_string(), + ) + .await + .expect("Couldn't connect to identity service"); + + // Initial device list check + let initial_device_list = + get_device_list_history(&mut auth_client, &primary_device.user_id) + .await + .into_iter() + .map(|device_list| device_list.devices) + .next() + .expect("Expected to get single device list update"); + + assert!(initial_device_list.len() == 1, "Expected single device"); + let primary_device_id = initial_device_list[0].clone(); + + // perform update by adding a new device + let raw_update_payload = json!({ + "devices": [primary_device_id, "device2"], + "timestamp": 123456789, + }); + let update_payload = json!({ + "rawDeviceList": serde_json::to_string(&raw_update_payload).unwrap(), + }); + let update_request = UpdateDeviceListRequest { + new_device_list: serde_json::to_string(&update_payload) + .expect("failed to serialize payload"), + }; + auth_client + .update_device_list_for_user(update_request) + .await + .expect("Update device list RPC failed"); + + // get device list again + let last_device_list = + get_device_list_history(&mut auth_client, &primary_device.user_id).await; + let last_device_list = last_device_list + .last() + .expect("Failed to get last device list update"); + + // check that the device list is properly updated + assert_eq!( + last_device_list.devices, + vec![primary_device_id, "device2".into()] + ); +} + // See GetDeviceListResponse in identity_authenticated.proto // for details on the response format. #[derive(Deserialize)] @@ -111,10 +155,26 @@ } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] -struct DeviceListUpdate { +struct SignedDeviceList { raw_device_list: String, } +impl SignedDeviceList { + fn into_raw(self) -> RawDeviceList { + self + .raw_device_list + .parse() + .expect("Failed to parse raw device list") + } +} + +impl FromStr for SignedDeviceList { + type Err = serde_json::Error; + fn from_str(s: &str) -> Result { + serde_json::from_str(s) + } +} + impl FromStr for RawDeviceList { type Err = serde_json::Error; fn from_str(s: &str) -> Result { @@ -123,3 +183,29 @@ serde_json::from_str(&s.replace(r#"\""#, r#"""#)) } } + +async fn get_device_list_history( + client: &mut ChainedInterceptedAuthClient, + user_id: &str, +) -> Vec { + let request = GetDeviceListRequest { + user_id: user_id.to_string(), + since_timestamp: None, + }; + + let response = client + .get_device_list_for_user(request) + .await + .expect("Get device list request failed") + .into_inner(); + + response + .device_list_updates + .into_iter() + .map(|update| { + SignedDeviceList::from_str(&update) + .expect("Failed to parse device list update") + .into_raw() + }) + .collect() +}