feat: sytests
This commit is contained in:
		
							parent
							
								
									8e041f90dd
								
							
						
					
					
						commit
						00a9424719
					
				
					 13 changed files with 1339 additions and 36 deletions
				
			
		
							
								
								
									
										4
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							|  | @ -1216,7 +1216,7 @@ dependencies = [ | |||
| [[package]] | ||||
| name = "ruma-federation-api" | ||||
| version = "0.0.1" | ||||
| source = "git+https://github.com/ruma/ruma-federation-api.git#ccbf216f39bbbaa59131cc200eae5bd18aa1947c" | ||||
| source = "git+https://github.com/ruma/ruma-federation-api.git?rev=ccbf216f39bbbaa59131cc200eae5bd18aa1947c#ccbf216f39bbbaa59131cc200eae5bd18aa1947c" | ||||
| dependencies = [ | ||||
|  "js_int", | ||||
|  "ruma-api", | ||||
|  | @ -1253,7 +1253,7 @@ dependencies = [ | |||
| [[package]] | ||||
| name = "ruma-signatures" | ||||
| version = "0.6.0-dev.1" | ||||
| source = "git+https://github.com/ruma/ruma-signatures.git#1ca545cba8dfd43e0fc8e3c18e1311fb73390a97" | ||||
| source = "git+https://github.com/ruma/ruma-signatures.git?rev=1ca545cba8dfd43e0fc8e3c18e1311fb73390a97#1ca545cba8dfd43e0fc8e3c18e1311fb73390a97" | ||||
| dependencies = [ | ||||
|  "base64 0.12.1", | ||||
|  "ring", | ||||
|  |  | |||
|  | @ -18,8 +18,8 @@ ruma-client-api = "0.8.0" | |||
| ruma-identifiers = "0.16.1" | ||||
| ruma-api = "0.16.0" | ||||
| ruma-events = "0.21.0" | ||||
| ruma-signatures = { git = "https://github.com/ruma/ruma-signatures.git" } | ||||
| ruma-federation-api = { git = "https://github.com/ruma/ruma-federation-api.git" } | ||||
| ruma-signatures = { git = "https://github.com/ruma/ruma-signatures.git", rev = "1ca545cba8dfd43e0fc8e3c18e1311fb73390a97" } | ||||
| ruma-federation-api = { git = "https://github.com/ruma/ruma-federation-api.git", rev = "ccbf216f39bbbaa59131cc200eae5bd18aa1947c" } | ||||
| log = "0.4.8" | ||||
| sled = "0.31.0" | ||||
| directories = "2.0.2" | ||||
|  |  | |||
|  | @ -66,7 +66,7 @@ pub fn get_register_available_route( | |||
| ) -> MatrixResult<get_username_availability::Response> { | ||||
|     // Validate user id
 | ||||
|     let user_id: UserId = | ||||
|         match (*format!("@{}:{}", body.username.clone(), db.globals.hostname())).try_into() { | ||||
|         match (*format!("@{}:{}", body.username.clone(), db.globals.server_name())).try_into() { | ||||
|             Err(_) => { | ||||
|                 debug!("Username invalid"); | ||||
|                 return MatrixResult(Err(Error { | ||||
|  | @ -117,7 +117,7 @@ pub fn register_route( | |||
|         body.username | ||||
|             .clone() | ||||
|             .unwrap_or_else(|| utils::random_string(GUEST_NAME_LENGTH)), | ||||
|         db.globals.hostname() | ||||
|         db.globals.server_name() | ||||
|     )) | ||||
|     .try_into() | ||||
|     { | ||||
|  | @ -229,7 +229,7 @@ pub fn login_route( | |||
|             (body.user.clone(), body.login_info.clone()) | ||||
|         { | ||||
|             if !username.contains(':') { | ||||
|                 username = format!("@{}:{}", username, db.globals.hostname()); | ||||
|                 username = format!("@{}:{}", username, db.globals.server_name()); | ||||
|             } | ||||
|             if let Ok(user_id) = (*username).try_into() { | ||||
|                 if let Some(hash) = db.users.password_hash(&user_id).unwrap() { | ||||
|  | @ -288,7 +288,7 @@ pub fn login_route( | |||
|     MatrixResult(Ok(login::Response { | ||||
|         user_id, | ||||
|         access_token: token, | ||||
|         home_server: Some(db.globals.hostname().to_owned()), | ||||
|         home_server: Some(db.globals.server_name().to_owned()), | ||||
|         device_id, | ||||
|         well_known: None, | ||||
|     })) | ||||
|  | @ -769,7 +769,7 @@ pub fn create_room_route( | |||
|     body: Ruma<create_room::Request>, | ||||
| ) -> MatrixResult<create_room::Response> { | ||||
|     // TODO: check if room is unique
 | ||||
|     let room_id = RoomId::try_from(db.globals.hostname()).expect("host is valid"); | ||||
|     let room_id = RoomId::try_from(db.globals.server_name()).expect("host is valid"); | ||||
|     let user_id = body.user_id.as_ref().expect("user is authenticated"); | ||||
| 
 | ||||
|     db.rooms | ||||
|  | @ -858,7 +858,7 @@ pub fn get_alias_route( | |||
|     _room_alias: String, | ||||
| ) -> MatrixResult<get_alias::Response> { | ||||
|     // TODO
 | ||||
|     let room_id = if body.room_alias.server_name() == db.globals.hostname() { | ||||
|     let room_id = if body.room_alias.server_name() == db.globals.server_name() { | ||||
|         match body.room_alias.alias() { | ||||
|             "conduit" => "!lgOCCXQKtXOAPlAlG5:conduit.rs", | ||||
|             _ => { | ||||
|  | @ -923,7 +923,7 @@ pub fn join_room_by_id_or_alias_route( | |||
|     let room_id = match RoomId::try_from(body.room_id_or_alias.clone()) { | ||||
|         Ok(room_id) => room_id, | ||||
|         Err(room_alias) => { | ||||
|             if room_alias.server_name() == db.globals.hostname() { | ||||
|             if room_alias.server_name() == db.globals.server_name() { | ||||
|                 return MatrixResult(Err(Error { | ||||
|                     kind: ErrorKind::NotFound, | ||||
|                     message: "Room alias not found.".to_owned(), | ||||
|  |  | |||
|  | @ -7,6 +7,8 @@ pub(self) mod users; | |||
| use directories::ProjectDirs; | ||||
| use std::fs::remove_dir_all; | ||||
| 
 | ||||
| use rocket::Config; | ||||
| 
 | ||||
| pub struct Database { | ||||
|     pub globals: globals::Globals, | ||||
|     pub users: users::Users, | ||||
|  | @ -18,26 +20,38 @@ pub struct Database { | |||
| 
 | ||||
| impl Database { | ||||
|     /// Tries to remove the old database but ignores all errors.
 | ||||
|     pub fn try_remove(hostname: &str) { | ||||
|     pub fn try_remove(server_name: &str) { | ||||
|         let mut path = ProjectDirs::from("xyz", "koesters", "conduit") | ||||
|             .unwrap() | ||||
|             .data_dir() | ||||
|             .to_path_buf(); | ||||
|         path.push(hostname); | ||||
|         path.push(server_name); | ||||
|         let _ = remove_dir_all(path); | ||||
|     } | ||||
| 
 | ||||
|     /// Load an existing database or create a new one.
 | ||||
|     pub fn load_or_create(hostname: &str) -> Self { | ||||
|         let mut path = ProjectDirs::from("xyz", "koesters", "conduit") | ||||
|     pub fn load_or_create(config: &Config) -> Self { | ||||
|         let server_name = config.get_str("server_name").unwrap_or("localhost"); | ||||
| 
 | ||||
|         let path = config | ||||
|             .get_str("database_path") | ||||
|             .map(|x| x.to_owned()) | ||||
|             .unwrap_or_else(|_| { | ||||
|                 let path = ProjectDirs::from("xyz", "koesters", "conduit") | ||||
|                     .unwrap() | ||||
|                     .data_dir() | ||||
|             .to_path_buf(); | ||||
|         path.push(hostname); | ||||
|                     .join(server_name); | ||||
|                 path.to_str().unwrap().to_owned() | ||||
|             }); | ||||
| 
 | ||||
|         let db = sled::open(&path).unwrap(); | ||||
|         log::info!("Opened sled database at {}", path); | ||||
| 
 | ||||
|         Self { | ||||
|             globals: globals::Globals::load(db.open_tree("global").unwrap(), hostname.to_owned()), | ||||
|             globals: globals::Globals::load( | ||||
|                 db.open_tree("global").unwrap(), | ||||
|                 server_name.to_owned(), | ||||
|             ), | ||||
|             users: users::Users { | ||||
|                 userid_password: db.open_tree("userid_password").unwrap(), | ||||
|                 userdeviceids: db.open_tree("userdeviceids").unwrap(), | ||||
|  |  | |||
|  | @ -4,13 +4,13 @@ pub const COUNTER: &str = "c"; | |||
| 
 | ||||
| pub struct Globals { | ||||
|     pub(super) globals: sled::Tree, | ||||
|     hostname: String, | ||||
|     server_name: String, | ||||
|     keypair: ruma_signatures::Ed25519KeyPair, | ||||
|     reqwest_client: reqwest::Client, | ||||
| } | ||||
| 
 | ||||
| impl Globals { | ||||
|     pub fn load(globals: sled::Tree, hostname: String) -> Self { | ||||
|     pub fn load(globals: sled::Tree, server_name: String) -> Self { | ||||
|         let keypair = ruma_signatures::Ed25519KeyPair::new( | ||||
|             &*globals | ||||
|                 .update_and_fetch("keypair", utils::generate_keypair) | ||||
|  | @ -22,15 +22,15 @@ impl Globals { | |||
| 
 | ||||
|         Self { | ||||
|             globals, | ||||
|             hostname, | ||||
|             server_name, | ||||
|             keypair, | ||||
|             reqwest_client: reqwest::Client::new(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Returns the hostname of the server.
 | ||||
|     pub fn hostname(&self) -> &str { | ||||
|         &self.hostname | ||||
|     /// Returns the server_name of the server.
 | ||||
|     pub fn server_name(&self) -> &str { | ||||
|         &self.server_name | ||||
|     } | ||||
| 
 | ||||
|     /// Returns this server's keypair.
 | ||||
|  |  | |||
|  | @ -216,7 +216,7 @@ impl Rooms { | |||
|             event_id: EventId::try_from("$thiswillbefilledinlater").expect("we know this is valid"), | ||||
|             room_id: room_id.clone(), | ||||
|             sender: sender.clone(), | ||||
|             origin: globals.hostname().to_owned(), | ||||
|             origin: globals.server_name().to_owned(), | ||||
|             origin_server_ts: utils::millis_since_unix_epoch() | ||||
|                 .try_into() | ||||
|                 .expect("this only fails many years in the future"), | ||||
|  | @ -245,7 +245,11 @@ impl Rooms { | |||
|         .expect("ruma's reference hashes are correct"); | ||||
| 
 | ||||
|         let mut pdu_json = serde_json::to_value(&pdu)?; | ||||
|         ruma_signatures::hash_and_sign_event(globals.hostname(), globals.keypair(), &mut pdu_json) | ||||
|         ruma_signatures::hash_and_sign_event( | ||||
|             globals.server_name(), | ||||
|             globals.keypair(), | ||||
|             &mut pdu_json, | ||||
|         ) | ||||
|         .expect("our new event can be hashed and signed"); | ||||
| 
 | ||||
|         self.replace_pdu_leaves(&room_id, &pdu.event_id)?; | ||||
|  |  | |||
|  | @ -75,8 +75,7 @@ fn setup_rocket() -> rocket::Rocket { | |||
|             ], | ||||
|         ) | ||||
|         .attach(AdHoc::on_attach("Config", |rocket| { | ||||
|             let hostname = rocket.config().get_str("hostname").unwrap_or("localhost"); | ||||
|             let data = Database::load_or_create(&hostname); | ||||
|             let data = Database::load_or_create(&rocket.config()); | ||||
| 
 | ||||
|             Ok(rocket.manage(data)) | ||||
|         })) | ||||
|  |  | |||
|  | @ -55,12 +55,12 @@ pub async fn send_request<T: Endpoint>( | |||
| 
 | ||||
|     request_map.insert("method".to_owned(), T::METADATA.method.to_string().into()); | ||||
|     request_map.insert("uri".to_owned(), T::METADATA.path.into()); | ||||
|     request_map.insert("origin".to_owned(), db.globals.hostname().into()); | ||||
|     request_map.insert("origin".to_owned(), db.globals.server_name().into()); | ||||
|     request_map.insert("destination".to_owned(), destination.into()); | ||||
| 
 | ||||
|     let mut request_json = request_map.into(); | ||||
|     ruma_signatures::sign_json( | ||||
|         db.globals.hostname(), | ||||
|         db.globals.server_name(), | ||||
|         db.globals.keypair(), | ||||
|         &mut request_json, | ||||
|     ) | ||||
|  | @ -82,7 +82,7 @@ pub async fn send_request<T: Endpoint>( | |||
|             AUTHORIZATION, | ||||
|             HeaderValue::from_str(&format!( | ||||
|                 "X-Matrix origin={},key=\"{}\",sig=\"{}\"", | ||||
|                 db.globals.hostname(), | ||||
|                 db.globals.server_name(), | ||||
|                 s.0, | ||||
|                 s.1 | ||||
|             )) | ||||
|  | @ -156,7 +156,7 @@ pub fn get_server_keys(db: State<'_, Database>) -> Json<String> { | |||
|     ); | ||||
|     let mut response = serde_json::from_slice( | ||||
|         http::Response::try_from(get_server_keys::Response { | ||||
|             server_name: db.globals.hostname().to_owned(), | ||||
|             server_name: db.globals.server_name().to_owned(), | ||||
|             verify_keys, | ||||
|             old_verify_keys: BTreeMap::new(), | ||||
|             signatures: BTreeMap::new(), | ||||
|  | @ -166,7 +166,7 @@ pub fn get_server_keys(db: State<'_, Database>) -> Json<String> { | |||
|         .body(), | ||||
|     ) | ||||
|     .unwrap(); | ||||
|     ruma_signatures::sign_json(db.globals.hostname(), db.globals.keypair(), &mut response).unwrap(); | ||||
|     ruma_signatures::sign_json(db.globals.server_name(), db.globals.keypair(), &mut response).unwrap(); | ||||
|     Json(response.to_string()) | ||||
| } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										836
									
								
								sytest/are-we-synapse-yet.list
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										836
									
								
								sytest/are-we-synapse-yet.list
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,836 @@ | |||
| reg GET /register yields a set of flows | ||||
| reg POST /register can create a user | ||||
| reg POST /register downcases capitals in usernames | ||||
| reg POST /register returns the same device_id as that in the request | ||||
| reg POST /register rejects registration of usernames with '!' | ||||
| reg POST /register rejects registration of usernames with '"' | ||||
| reg POST /register rejects registration of usernames with ':' | ||||
| reg POST /register rejects registration of usernames with '?' | ||||
| reg POST /register rejects registration of usernames with '\' | ||||
| reg POST /register rejects registration of usernames with '@' | ||||
| reg POST /register rejects registration of usernames with '[' | ||||
| reg POST /register rejects registration of usernames with ']' | ||||
| reg POST /register rejects registration of usernames with '{' | ||||
| reg POST /register rejects registration of usernames with '|' | ||||
| reg POST /register rejects registration of usernames with '}' | ||||
| reg POST /register rejects registration of usernames with '£' | ||||
| reg POST /register rejects registration of usernames with 'é' | ||||
| reg POST /register rejects registration of usernames with '\n' | ||||
| reg POST /register rejects registration of usernames with ''' | ||||
| reg POST /r0/admin/register with shared secret | ||||
| reg POST /r0/admin/register admin with shared secret | ||||
| reg POST /r0/admin/register with shared secret downcases capitals | ||||
| reg POST /r0/admin/register with shared secret disallows symbols | ||||
| reg POST rejects invalid utf-8 in JSON | ||||
| log GET /login yields a set of flows | ||||
| log POST /login can log in as a user | ||||
| log POST /login returns the same device_id as that in the request | ||||
| log POST /login can log in as a user with just the local part of the id | ||||
| log POST /login as non-existing user is rejected | ||||
| log POST /login wrong password is rejected | ||||
| log Interactive authentication types include SSO | ||||
| log Can perform interactive authentication with SSO | ||||
| log The user must be consistent through an interactive authentication session with SSO | ||||
| log The operation must be consistent through an interactive authentication session | ||||
| v1s GET /events initially | ||||
| v1s GET /initialSync initially | ||||
| csa Version responds 200 OK with valid structure | ||||
| pro PUT /profile/:user_id/displayname sets my name | ||||
| pro GET /profile/:user_id/displayname publicly accessible | ||||
| pro PUT /profile/:user_id/avatar_url sets my avatar | ||||
| pro GET /profile/:user_id/avatar_url publicly accessible | ||||
| dev GET /device/{deviceId} | ||||
| dev GET /device/{deviceId} gives a 404 for unknown devices | ||||
| dev GET /devices | ||||
| dev PUT /device/{deviceId} updates device fields | ||||
| dev PUT /device/{deviceId} gives a 404 for unknown devices | ||||
| dev DELETE /device/{deviceId} | ||||
| dev DELETE /device/{deviceId} requires UI auth user to match device owner | ||||
| dev DELETE /device/{deviceId} with no body gives a 401 | ||||
| dev The deleted device must be consistent through an interactive auth session | ||||
| dev Users receive device_list updates for their own devices | ||||
| pre GET /presence/:user_id/status fetches initial status | ||||
| pre PUT /presence/:user_id/status updates my presence | ||||
| crm POST /createRoom makes a public room | ||||
| crm POST /createRoom makes a private room | ||||
| crm POST /createRoom makes a private room with invites | ||||
| crm POST /createRoom makes a room with a name | ||||
| crm POST /createRoom makes a room with a topic | ||||
| syn Can /sync newly created room | ||||
| crm POST /createRoom creates a room with the given version | ||||
| crm POST /createRoom rejects attempts to create rooms with numeric versions | ||||
| crm POST /createRoom rejects attempts to create rooms with unknown versions | ||||
| crm POST /createRoom ignores attempts to set the room version via creation_content | ||||
| mem GET /rooms/:room_id/state/m.room.member/:user_id fetches my membership | ||||
| mem GET /rooms/:room_id/state/m.room.member/:user_id?format=event fetches my membership event | ||||
| rst GET /rooms/:room_id/state/m.room.power_levels fetches powerlevels | ||||
| mem GET /rooms/:room_id/joined_members fetches my membership | ||||
| v1s GET /rooms/:room_id/initialSync fetches initial sync state | ||||
| pub GET /publicRooms lists newly-created room | ||||
| ali GET /directory/room/:room_alias yields room ID | ||||
| mem GET /joined_rooms lists newly-created room | ||||
| rst POST /rooms/:room_id/state/m.room.name sets name | ||||
| rst GET /rooms/:room_id/state/m.room.name gets name | ||||
| rst POST /rooms/:room_id/state/m.room.topic sets topic | ||||
| rst GET /rooms/:room_id/state/m.room.topic gets topic | ||||
| rst GET /rooms/:room_id/state fetches entire room state | ||||
| crm POST /createRoom with creation content | ||||
| ali PUT /directory/room/:room_alias creates alias | ||||
| nsp GET /rooms/:room_id/aliases lists aliases | ||||
| jon POST /rooms/:room_id/join can join a room | ||||
| jon POST /join/:room_alias can join a room | ||||
| jon POST /join/:room_id can join a room | ||||
| jon POST /join/:room_id can join a room with custom content | ||||
| jon POST /join/:room_alias can join a room with custom content | ||||
| lev POST /rooms/:room_id/leave can leave a room | ||||
| inv POST /rooms/:room_id/invite can send an invite | ||||
| ban POST /rooms/:room_id/ban can ban a user | ||||
| snd POST /rooms/:room_id/send/:event_type sends a message | ||||
| snd PUT /rooms/:room_id/send/:event_type/:txn_id sends a message | ||||
| snd PUT /rooms/:room_id/send/:event_type/:txn_id deduplicates the same txn id | ||||
| get GET /rooms/:room_id/messages returns a message | ||||
| get GET /rooms/:room_id/messages lazy loads members correctly | ||||
| typ PUT /rooms/:room_id/typing/:user_id sets typing notification | ||||
| rst GET /rooms/:room_id/state/m.room.power_levels can fetch levels | ||||
| rst PUT /rooms/:room_id/state/m.room.power_levels can set levels | ||||
| rst PUT power_levels should not explode if the old power levels were empty | ||||
| rst Both GET and PUT work | ||||
| rct POST /rooms/:room_id/receipt can create receipts | ||||
| red POST /rooms/:room_id/read_markers can create read marker | ||||
| med POST /media/v1/upload can create an upload | ||||
| med GET /media/v1/download can fetch the value again | ||||
| cap GET /capabilities is present and well formed for registered user | ||||
| cap GET /r0/capabilities is not public | ||||
| reg Register with a recaptcha | ||||
| reg registration is idempotent, without username specified | ||||
| reg registration is idempotent, with username specified | ||||
| reg registration remembers parameters | ||||
| reg registration accepts non-ascii passwords | ||||
| reg registration with inhibit_login inhibits login | ||||
| reg User signups are forbidden from starting with '_' | ||||
| reg Can register using an email address | ||||
| log Can login with 3pid and password using m.login.password | ||||
| log login types include SSO | ||||
| log /login/cas/redirect redirects if the old m.login.cas login type is listed | ||||
| log Can login with new user via CAS | ||||
| lox Can logout current device | ||||
| lox Can logout all devices | ||||
| lox Request to logout with invalid an access token is rejected | ||||
| lox Request to logout without an access token is rejected | ||||
| log After changing password, can't log in with old password | ||||
| log After changing password, can log in with new password | ||||
| log After changing password, existing session still works | ||||
| log After changing password, a different session no longer works by default | ||||
| log After changing password, different sessions can optionally be kept | ||||
| psh Pushers created with a different access token are deleted on password change | ||||
| psh Pushers created with a the same access token are not deleted on password change | ||||
| acc Can deactivate account | ||||
| acc Can't deactivate account with wrong password | ||||
| acc After deactivating account, can't log in with password | ||||
| acc After deactivating account, can't log in with an email | ||||
| v1s initialSync sees my presence status | ||||
| pre Presence change reports an event to myself | ||||
| pre Friends presence changes reports events | ||||
| crm Room creation reports m.room.create to myself | ||||
| crm Room creation reports m.room.member to myself | ||||
| rst Setting room topic reports m.room.topic to myself | ||||
| v1s Global initialSync | ||||
| v1s Global initialSync with limit=0 gives no messages | ||||
| v1s Room initialSync | ||||
| v1s Room initialSync with limit=0 gives no messages | ||||
| rst Setting state twice is idempotent | ||||
| jon Joining room twice is idempotent | ||||
| syn New room members see their own join event | ||||
| v1s New room members see existing users' presence in room initialSync | ||||
| syn Existing members see new members' join events | ||||
| syn Existing members see new members' presence | ||||
| v1s All room members see all room members' presence in global initialSync | ||||
| f,jon Remote users can join room by alias | ||||
| syn New room members see their own join event | ||||
| v1s New room members see existing members' presence in room initialSync | ||||
| syn Existing members see new members' join events | ||||
| syn Existing members see new member's presence | ||||
| v1s New room members see first user's profile information in global initialSync | ||||
| v1s New room members see first user's profile information in per-room initialSync | ||||
| f,jon Remote users may not join unfederated rooms | ||||
| syn Local room members see posted message events | ||||
| v1s Fetching eventstream a second time doesn't yield the message again | ||||
| syn Local non-members don't see posted message events | ||||
| get Local room members can get room messages | ||||
| f,syn Remote room members also see posted message events | ||||
| f,get Remote room members can get room messages | ||||
| get Message history can be paginated | ||||
| f,get Message history can be paginated over federation | ||||
| eph Ephemeral messages received from clients are correctly expired | ||||
| ali Room aliases can contain Unicode | ||||
| f,ali Remote room alias queries can handle Unicode | ||||
| ali Canonical alias can be set | ||||
| ali Canonical alias can include alt_aliases | ||||
| ali Regular users can add and delete aliases in the default room configuration | ||||
| ali Regular users can add and delete aliases when m.room.aliases is restricted | ||||
| ali Deleting a non-existent alias should return a 404 | ||||
| ali Users can't delete other's aliases | ||||
| ali Users with sufficient power-level can delete other's aliases | ||||
| ali Can delete canonical alias | ||||
| ali Alias creators can delete alias with no ops | ||||
| ali Alias creators can delete canonical alias with no ops | ||||
| ali Only room members can list aliases of a room | ||||
| inv Can invite users to invite-only rooms | ||||
| inv Uninvited users cannot join the room | ||||
| inv Invited user can reject invite | ||||
| f,inv Invited user can reject invite over federation | ||||
| f,inv Invited user can reject invite over federation several times | ||||
| inv Invited user can reject invite for empty room | ||||
| f,inv Invited user can reject invite over federation for empty room | ||||
| inv Invited user can reject local invite after originator leaves | ||||
| inv Invited user can see room metadata | ||||
| f,inv Remote invited user can see room metadata | ||||
| inv Users cannot invite themselves to a room | ||||
| inv Users cannot invite a user that is already in the room | ||||
| ban Banned user is kicked and may not rejoin until unbanned | ||||
| f,ban Remote banned user is kicked and may not rejoin until unbanned | ||||
| ban 'ban' event respects room powerlevel | ||||
| plv setting 'm.room.name' respects room powerlevel | ||||
| plv setting 'm.room.power_levels' respects room powerlevel (2 subtests) | ||||
| plv Unprivileged users can set m.room.topic if it only needs level 0 | ||||
| plv Users cannot set ban powerlevel higher than their own (2 subtests) | ||||
| plv Users cannot set kick powerlevel higher than their own (2 subtests) | ||||
| plv Users cannot set redact powerlevel higher than their own (2 subtests) | ||||
| v1s Check that event streams started after a client joined a room work (SYT-1) | ||||
| v1s Event stream catches up fully after many messages | ||||
| xxx POST /rooms/:room_id/redact/:event_id as power user redacts message | ||||
| xxx POST /rooms/:room_id/redact/:event_id as original message sender redacts message | ||||
| xxx POST /rooms/:room_id/redact/:event_id as random user does not redact message | ||||
| xxx POST /redact disallows redaction of event in different room | ||||
| xxx Redaction of a redaction redacts the redaction reason | ||||
| v1s A departed room is still included in /initialSync (SPEC-216) | ||||
| v1s Can get rooms/{roomId}/initialSync for a departed room (SPEC-216) | ||||
| rst Can get rooms/{roomId}/state for a departed room (SPEC-216) | ||||
| mem Can get rooms/{roomId}/members for a departed room (SPEC-216) | ||||
| get Can get rooms/{roomId}/messages for a departed room (SPEC-216) | ||||
| rst Can get 'm.room.name' state for a departed room (SPEC-216) | ||||
| syn Getting messages going forward is limited for a departed room (SPEC-216) | ||||
| 3pd Can invite existing 3pid | ||||
| 3pd Can invite existing 3pid with no ops into a private room | ||||
| 3pd Can invite existing 3pid in createRoom | ||||
| 3pd Can invite unbound 3pid | ||||
| f,3pd Can invite unbound 3pid over federation | ||||
| 3pd Can invite unbound 3pid with no ops into a private room | ||||
| f,3pd Can invite unbound 3pid over federation with no ops into a private room | ||||
| f,3pd Can invite unbound 3pid over federation with users from both servers | ||||
| 3pd Can accept unbound 3pid invite after inviter leaves | ||||
| 3pd Can accept third party invite with /join | ||||
| 3pd 3pid invite join with wrong but valid signature are rejected | ||||
| 3pd 3pid invite join valid signature but revoked keys are rejected | ||||
| 3pd 3pid invite join valid signature but unreachable ID server are rejected | ||||
| gst Guest user cannot call /events globally | ||||
| gst Guest users can join guest_access rooms | ||||
| gst Guest users can send messages to guest_access rooms if joined | ||||
| gst Guest user calling /events doesn't tightloop | ||||
| gst Guest users are kicked from guest_access rooms on revocation of guest_access | ||||
| gst Guest user can set display names | ||||
| gst Guest users are kicked from guest_access rooms on revocation of guest_access over federation | ||||
| gst Guest user can upgrade to fully featured user | ||||
| gst Guest user cannot upgrade other users | ||||
| pub GET /publicRooms lists rooms | ||||
| pub GET /publicRooms includes avatar URLs | ||||
| gst Guest users can accept invites to private rooms over federation | ||||
| gst Guest users denied access over federation if guest access prohibited | ||||
| mem Room members can override their displayname on a room-specific basis | ||||
| mem Room members can join a room with an overridden displayname | ||||
| mem Users cannot kick users from a room they are not in | ||||
| mem Users cannot kick users who have already left a room | ||||
| typ Typing notification sent to local room members | ||||
| f,typ Typing notifications also sent to remote room members | ||||
| typ Typing can be explicitly stopped | ||||
| rct Read receipts are visible to /initialSync | ||||
| rct Read receipts are sent as events | ||||
| rct Receipts must be m.read | ||||
| pro displayname updates affect room member events | ||||
| pro avatar_url updates affect room member events | ||||
| gst m.room.history_visibility == "world_readable" allows/forbids appropriately for Guest users | ||||
| gst m.room.history_visibility == "shared" allows/forbids appropriately for Guest users | ||||
| gst m.room.history_visibility == "invited" allows/forbids appropriately for Guest users | ||||
| gst m.room.history_visibility == "joined" allows/forbids appropriately for Guest users | ||||
| gst m.room.history_visibility == "default" allows/forbids appropriately for Guest users | ||||
| gst Guest non-joined user cannot call /events on shared room | ||||
| gst Guest non-joined user cannot call /events on invited room | ||||
| gst Guest non-joined user cannot call /events on joined room | ||||
| gst Guest non-joined user cannot call /events on default room | ||||
| gst Guest non-joined user can call /events on world_readable room | ||||
| gst Guest non-joined users can get state for world_readable rooms | ||||
| gst Guest non-joined users can get individual state for world_readable rooms | ||||
| gst Guest non-joined users cannot room initalSync for non-world_readable rooms | ||||
| gst Guest non-joined users can room initialSync for world_readable rooms | ||||
| gst Guest non-joined users can get individual state for world_readable rooms after leaving | ||||
| gst Guest non-joined users cannot send messages to guest_access rooms if not joined | ||||
| gst Guest users can sync from world_readable guest_access rooms if joined | ||||
| gst Guest users can sync from shared guest_access rooms if joined | ||||
| gst Guest users can sync from invited guest_access rooms if joined | ||||
| gst Guest users can sync from joined guest_access rooms if joined | ||||
| gst Guest users can sync from default guest_access rooms if joined | ||||
| ath m.room.history_visibility == "world_readable" allows/forbids appropriately for Real users | ||||
| ath m.room.history_visibility == "shared" allows/forbids appropriately for Real users | ||||
| ath m.room.history_visibility == "invited" allows/forbids appropriately for Real users | ||||
| ath m.room.history_visibility == "joined" allows/forbids appropriately for Real users | ||||
| ath m.room.history_visibility == "default" allows/forbids appropriately for Real users | ||||
| ath Real non-joined user cannot call /events on shared room | ||||
| ath Real non-joined user cannot call /events on invited room | ||||
| ath Real non-joined user cannot call /events on joined room | ||||
| ath Real non-joined user cannot call /events on default room | ||||
| ath Real non-joined user can call /events on world_readable room | ||||
| ath Real non-joined users can get state for world_readable rooms | ||||
| ath Real non-joined users can get individual state for world_readable rooms | ||||
| ath Real non-joined users cannot room initalSync for non-world_readable rooms | ||||
| ath Real non-joined users can room initialSync for world_readable rooms | ||||
| ath Real non-joined users can get individual state for world_readable rooms after leaving | ||||
| ath Real non-joined users cannot send messages to guest_access rooms if not joined | ||||
| ath Real users can sync from world_readable guest_access rooms if joined | ||||
| ath Real users can sync from shared guest_access rooms if joined | ||||
| ath Real users can sync from invited guest_access rooms if joined | ||||
| ath Real users can sync from joined guest_access rooms if joined | ||||
| ath Real users can sync from default guest_access rooms if joined | ||||
| ath Only see history_visibility changes on boundaries | ||||
| f,ath Backfill works correctly with history visibility set to joined | ||||
| fgt Forgotten room messages cannot be paginated | ||||
| fgt Forgetting room does not show up in v2 /sync | ||||
| fgt Can forget room you've been kicked from | ||||
| fgt Can't forget room you're still in | ||||
| mem Can re-join room if re-invited | ||||
| ath Only original members of the room can see messages from erased users | ||||
| mem /joined_rooms returns only joined rooms | ||||
| mem /joined_members return joined members | ||||
| ctx /context/ on joined room works | ||||
| ctx /context/ on non world readable room does not work | ||||
| ctx /context/ returns correct number of events | ||||
| ctx /context/ with lazy_load_members filter works | ||||
| get /event/ on joined room works | ||||
| get /event/ on non world readable room does not work | ||||
| get /event/ does not allow access to events before the user joined | ||||
| mem Can get rooms/{roomId}/members | ||||
| mem Can get rooms/{roomId}/members at a given point | ||||
| mem Can filter rooms/{roomId}/members | ||||
| upg /upgrade creates a new room | ||||
| upg /upgrade should preserve room visibility for public rooms | ||||
| upg /upgrade should preserve room visibility for private rooms | ||||
| upg /upgrade copies >100 power levels to the new room | ||||
| upg /upgrade copies the power levels to the new room | ||||
| upg /upgrade preserves the power level of the upgrading user in old and new rooms | ||||
| upg /upgrade copies important state to the new room | ||||
| upg /upgrade copies ban events to the new room | ||||
| upg local user has push rules copied to upgraded room | ||||
| f,upg remote user has push rules copied to upgraded room | ||||
| upg /upgrade moves aliases to the new room | ||||
| upg /upgrade moves remote aliases to the new room | ||||
| upg /upgrade preserves direct room state | ||||
| upg /upgrade preserves room federation ability | ||||
| upg /upgrade restricts power levels in the old room | ||||
| upg /upgrade restricts power levels in the old room when the old PLs are unusual | ||||
| upg /upgrade to an unknown version is rejected | ||||
| upg /upgrade is rejected if the user can't send state events | ||||
| upg /upgrade of a bogus room fails gracefully | ||||
| upg Cannot send tombstone event that points to the same room | ||||
| f,upg Local and remote users' homeservers remove a room from their public directory on upgrade | ||||
| rst Name/topic keys are correct | ||||
| f,pub Can get remote public room list | ||||
| pub Can paginate public room list | ||||
| pub Can search public room list | ||||
| syn Can create filter | ||||
| syn Can download filter | ||||
| syn Can sync | ||||
| syn Can sync a joined room | ||||
| syn Full state sync includes joined rooms | ||||
| syn Newly joined room is included in an incremental sync | ||||
| syn Newly joined room has correct timeline in incremental sync | ||||
| syn Newly joined room includes presence in incremental sync | ||||
| syn Get presence for newly joined members in incremental sync | ||||
| syn Can sync a room with a single message | ||||
| syn Can sync a room with a message with a transaction id | ||||
| syn A message sent after an initial sync appears in the timeline of an incremental sync. | ||||
| syn A filtered timeline reaches its limit | ||||
| syn Syncing a new room with a large timeline limit isn't limited | ||||
| syn A full_state incremental update returns only recent timeline | ||||
| syn A prev_batch token can be used in the v1 messages API | ||||
| syn A next_batch token can be used in the v1 messages API | ||||
| syn User sees their own presence in a sync | ||||
| syn User is offline if they set_presence=offline in their sync | ||||
| syn User sees updates to presence from other users in the incremental sync. | ||||
| syn State is included in the timeline in the initial sync | ||||
| f,syn State from remote users is included in the state in the initial sync | ||||
| syn Changes to state are included in an incremental sync | ||||
| syn Changes to state are included in an gapped incremental sync | ||||
| f,syn State from remote users is included in the timeline in an incremental sync | ||||
| syn A full_state incremental update returns all state | ||||
| syn When user joins a room the state is included in the next sync | ||||
| syn A change to displayname should not result in a full state sync | ||||
| syn A change to displayname should appear in incremental /sync | ||||
| syn When user joins a room the state is included in a gapped sync | ||||
| syn When user joins and leaves a room in the same batch, the full state is still included in the next sync | ||||
| syn Current state appears in timeline in private history | ||||
| syn Current state appears in timeline in private history with many messages before | ||||
| syn Current state appears in timeline in private history with many messages after | ||||
| syn Rooms a user is invited to appear in an initial sync | ||||
| syn Rooms a user is invited to appear in an incremental sync | ||||
| syn Newly joined room is included in an incremental sync after invite | ||||
| syn Sync can be polled for updates | ||||
| syn Sync is woken up for leaves | ||||
| syn Left rooms appear in the leave section of sync | ||||
| syn Newly left rooms appear in the leave section of incremental sync | ||||
| syn We should see our own leave event, even if history_visibility is restricted (SYN-662) | ||||
| syn We should see our own leave event when rejecting an invite, even if history_visibility is restricted (riot-web/3462) | ||||
| syn Newly left rooms appear in the leave section of gapped sync | ||||
| syn Previously left rooms don't appear in the leave section of sync | ||||
| syn Left rooms appear in the leave section of full state sync | ||||
| syn Archived rooms only contain history from before the user left | ||||
| syn Banned rooms appear in the leave section of sync | ||||
| syn Newly banned rooms appear in the leave section of incremental sync | ||||
| syn Newly banned rooms appear in the leave section of incremental sync | ||||
| syn Typing events appear in initial sync | ||||
| syn Typing events appear in incremental sync | ||||
| syn Typing events appear in gapped sync | ||||
| syn Read receipts appear in initial v2 /sync | ||||
| syn New read receipts appear in incremental v2 /sync | ||||
| syn Can pass a JSON filter as a query parameter | ||||
| syn Can request federation format via the filter | ||||
| syn Read markers appear in incremental v2 /sync | ||||
| syn Read markers appear in initial v2 /sync | ||||
| syn Read markers can be updated | ||||
| syn Lazy loading parameters in the filter are strictly boolean | ||||
| syn The only membership state included in an initial sync is for all the senders in the timeline | ||||
| syn The only membership state included in an incremental sync is for senders in the timeline | ||||
| syn The only membership state included in a gapped incremental sync is for senders in the timeline | ||||
| syn Gapped incremental syncs include all state changes | ||||
| syn Old leaves are present in gapped incremental syncs | ||||
| syn Leaves are present in non-gapped incremental syncs | ||||
| syn Old members are included in gappy incr LL sync if they start speaking | ||||
| syn Members from the gap are included in gappy incr LL sync | ||||
| syn We don't send redundant membership state across incremental syncs by default | ||||
| syn We do send redundant membership state across incremental syncs if asked | ||||
| syn Unnamed room comes with a name summary | ||||
| syn Named room comes with just joined member count summary | ||||
| syn Room summary only has 5 heroes | ||||
| syn Room summary counts change when membership changes | ||||
| rmv User can create and send/receive messages in a room with version 1 | ||||
| rmv User can create and send/receive messages in a room with version 1 (2 subtests) | ||||
| rmv local user can join room with version 1 | ||||
| rmv User can invite local user to room with version 1 | ||||
| rmv remote user can join room with version 1 | ||||
| rmv User can invite remote user to room with version 1 | ||||
| rmv Remote user can backfill in a room with version 1 | ||||
| rmv Can reject invites over federation for rooms with version 1 | ||||
| rmv Can receive redactions from regular users over federation in room version 1 | ||||
| rmv User can create and send/receive messages in a room with version 2 | ||||
| rmv User can create and send/receive messages in a room with version 2 (2 subtests) | ||||
| rmv local user can join room with version 2 | ||||
| rmv User can invite local user to room with version 2 | ||||
| rmv remote user can join room with version 2 | ||||
| rmv User can invite remote user to room with version 2 | ||||
| rmv Remote user can backfill in a room with version 2 | ||||
| rmv Can reject invites over federation for rooms with version 2 | ||||
| rmv Can receive redactions from regular users over federation in room version 2 | ||||
| rmv User can create and send/receive messages in a room with version 3 | ||||
| rmv User can create and send/receive messages in a room with version 3 (2 subtests) | ||||
| rmv local user can join room with version 3 | ||||
| rmv User can invite local user to room with version 3 | ||||
| rmv remote user can join room with version 3 | ||||
| rmv User can invite remote user to room with version 3 | ||||
| rmv Remote user can backfill in a room with version 3 | ||||
| rmv Can reject invites over federation for rooms with version 3 | ||||
| rmv Can receive redactions from regular users over federation in room version 3 | ||||
| rmv User can create and send/receive messages in a room with version 4 | ||||
| rmv User can create and send/receive messages in a room with version 4 (2 subtests) | ||||
| rmv local user can join room with version 4 | ||||
| rmv User can invite local user to room with version 4 | ||||
| rmv remote user can join room with version 4 | ||||
| rmv User can invite remote user to room with version 4 | ||||
| rmv Remote user can backfill in a room with version 4 | ||||
| rmv Can reject invites over federation for rooms with version 4 | ||||
| rmv Can receive redactions from regular users over federation in room version 4 | ||||
| rmv User can create and send/receive messages in a room with version 5 | ||||
| rmv User can create and send/receive messages in a room with version 5 (2 subtests) | ||||
| rmv local user can join room with version 5 | ||||
| rmv User can invite local user to room with version 5 | ||||
| rmv remote user can join room with version 5 | ||||
| rmv User can invite remote user to room with version 5 | ||||
| rmv Remote user can backfill in a room with version 5 | ||||
| rmv Can reject invites over federation for rooms with version 5 | ||||
| rmv Can receive redactions from regular users over federation in room version 5 | ||||
| pre Presence changes are reported to local room members | ||||
| f,pre Presence changes are also reported to remote room members | ||||
| pre Presence changes to UNAVAILABLE are reported to local room members | ||||
| f,pre Presence changes to UNAVAILABLE are reported to remote room members | ||||
| v1s Newly created users see their own presence in /initialSync (SYT-34) | ||||
| dvk Can upload device keys | ||||
| dvk Should reject keys claiming to belong to a different user | ||||
| dvk Can query device keys using POST | ||||
| dvk Can query specific device keys using POST | ||||
| dvk query for user with no keys returns empty key dict | ||||
| dvk Can claim one time key using POST | ||||
| f,dvk Can query remote device keys using POST | ||||
| f,dvk Can claim remote one time key using POST | ||||
| dvk Local device key changes appear in v2 /sync | ||||
| dvk Local new device changes appear in v2 /sync | ||||
| dvk Local delete device changes appear in v2 /sync | ||||
| dvk Local update device changes appear in v2 /sync | ||||
| dvk Can query remote device keys using POST after notification | ||||
| f,dev Device deletion propagates over federation | ||||
| f,dev If remote user leaves room, changes device and rejoins we see update in sync | ||||
| f,dev If remote user leaves room we no longer receive device updates | ||||
| dvk Local device key changes appear in /keys/changes | ||||
| dvk New users appear in /keys/changes | ||||
| f,dvk If remote user leaves room, changes device and rejoins we see update in /keys/changes | ||||
| dvk Get left notifs in sync and /keys/changes when other user leaves | ||||
| dvk Get left notifs for other users in sync and /keys/changes when user leaves | ||||
| f,dvk If user leaves room, remote user changes device and rejoins we see update in /sync and /keys/changes | ||||
| dvk Can create backup version | ||||
| dvk Can update backup version | ||||
| dvk Responds correctly when backup is empty | ||||
| dvk Can backup keys | ||||
| dvk Can update keys with better versions | ||||
| dvk Will not update keys with worse versions | ||||
| dvk Will not back up to an old backup version | ||||
| dvk Can delete backup | ||||
| dvk Deleted & recreated backups are empty | ||||
| dvk Can create more than 10 backup versions | ||||
| dvk Can upload self-signing keys | ||||
| dvk Fails to upload self-signing keys with no auth | ||||
| dvk Fails to upload self-signing key without master key | ||||
| dvk Changing master key notifies local users | ||||
| dvk Changing user-signing key notifies local users | ||||
| f,dvk can fetch self-signing keys over federation | ||||
| f,dvk uploading self-signing key notifies over federation | ||||
| f,dvk uploading signed devices gets propagated over federation | ||||
| tag Can add tag | ||||
| tag Can remove tag | ||||
| tag Can list tags for a room | ||||
| v1s Tags appear in the v1 /events stream | ||||
| v1s Tags appear in the v1 /initalSync | ||||
| v1s Tags appear in the v1 room initial sync | ||||
| tag Tags appear in an initial v2 /sync | ||||
| tag Newly updated tags appear in an incremental v2 /sync | ||||
| tag Deleted tags appear in an incremental v2 /sync | ||||
| tag local user has tags copied to the new room | ||||
| f,tag remote user has tags copied to the new room | ||||
| sch Can search for an event by body | ||||
| sch Can get context around search results | ||||
| sch Can back-paginate search results | ||||
| sch Search works across an upgraded room and its predecessor | ||||
| sch Search results with rank ordering do not include redacted events | ||||
| sch Search results with recent ordering do not include redacted events | ||||
| acc Can add account data | ||||
| acc Can add account data to room | ||||
| acc Can get account data without syncing | ||||
| acc Can get room account data without syncing | ||||
| v1s Latest account data comes down in /initialSync | ||||
| v1s Latest account data comes down in room initialSync | ||||
| v1s Account data appears in v1 /events stream | ||||
| v1s Room account data appears in v1 /events stream | ||||
| acc Latest account data appears in v2 /sync | ||||
| acc New account data appears in incremental v2 /sync | ||||
| oid Can generate a openid access_token that can be exchanged for information about a user | ||||
| oid Invalid openid access tokens are rejected | ||||
| oid Requests to userinfo without access tokens are rejected | ||||
| std Can send a message directly to a device using PUT /sendToDevice | ||||
| std Can recv a device message using /sync | ||||
| std Can recv device messages until they are acknowledged | ||||
| std Device messages with the same txn_id are deduplicated | ||||
| std Device messages wake up /sync | ||||
| std Can recv device messages over federation | ||||
| std Device messages over federation wake up /sync | ||||
| std Can send messages with a wildcard device id | ||||
| std Can send messages with a wildcard device id to two devices | ||||
| std Wildcard device messages wake up /sync | ||||
| std Wildcard device messages over federation wake up /sync | ||||
| adm /whois | ||||
| nsp /purge_history | ||||
| nsp /purge_history by ts | ||||
| nsp Can backfill purged history | ||||
| nsp Shutdown room | ||||
| ign Ignore user in existing room | ||||
| ign Ignore invite in full sync | ||||
| ign Ignore invite in incremental sync | ||||
| fky Checking local federation server | ||||
| fky Federation key API allows unsigned requests for keys | ||||
| fky Federation key API can act as a notary server via a GET request | ||||
| fky Federation key API can act as a notary server via a POST request | ||||
| fky Key notary server should return an expired key if it can't find any others | ||||
| fky Key notary server must not overwrite a valid key with a spurious result from the origin server | ||||
| fqu Non-numeric ports in server names are rejected | ||||
| fqu Outbound federation can query profile data | ||||
| fqu Inbound federation can query profile data | ||||
| fqu Outbound federation can query room alias directory | ||||
| fqu Inbound federation can query room alias directory | ||||
| fsj Outbound federation can query v1 /send_join | ||||
| fsj Outbound federation can query v2 /send_join | ||||
| fmj Outbound federation passes make_join failures through to the client | ||||
| fsj Inbound federation can receive v1 /send_join | ||||
| fsj Inbound federation can receive v2 /send_join | ||||
| fmj Inbound /v1/make_join rejects remote attempts to join local users to rooms | ||||
| fsj Inbound /v1/send_join rejects incorrectly-signed joins | ||||
| fsj Inbound /v1/send_join rejects joins from other servers | ||||
| fau Inbound federation rejects remote attempts to kick local users to rooms | ||||
| frv Inbound federation rejects attempts to join v1 rooms from servers without v1 support | ||||
| frv Inbound federation rejects attempts to join v2 rooms from servers lacking version support | ||||
| frv Inbound federation rejects attempts to join v2 rooms from servers only supporting v1 | ||||
| frv Inbound federation accepts attempts to join v2 rooms from servers with support | ||||
| frv Outbound federation correctly handles unsupported room versions | ||||
| frv A pair of servers can establish a join in a v2 room | ||||
| fsj Outbound federation rejects send_join responses with no m.room.create event | ||||
| frv Outbound federation rejects m.room.create events with an unknown room version | ||||
| fsj Event with an invalid signature in the send_join response should not cause room join to fail | ||||
| fed Outbound federation can send events | ||||
| fed Inbound federation can receive events | ||||
| fed Inbound federation can receive redacted events | ||||
| fed Ephemeral messages received from servers are correctly expired | ||||
| fed Events whose auth_events are in the wrong room do not mess up the room state | ||||
| fed Inbound federation can return events | ||||
| fed Inbound federation redacts events from erased users | ||||
| fme Outbound federation can request missing events | ||||
| fme Inbound federation can return missing events for world_readable visibility | ||||
| fme Inbound federation can return missing events for shared visibility | ||||
| fme Inbound federation can return missing events for invite visibility | ||||
| fme Inbound federation can return missing events for joined visibility | ||||
| fme outliers whose auth_events are in a different room are correctly rejected | ||||
| fbk Outbound federation can backfill events | ||||
| fbk Inbound federation can backfill events | ||||
| fbk Backfill checks the events requested belong to the room | ||||
| fbk Backfilled events whose prev_events are in a different room do not allow cross-room back-pagination | ||||
| fiv Outbound federation can send invites via v1 API | ||||
| fiv Outbound federation can send invites via v2 API | ||||
| fiv Inbound federation can receive invites via v1 API | ||||
| fiv Inbound federation can receive invites via v2 API | ||||
| fiv Inbound federation can receive invite and reject when remote replies with a 403 | ||||
| fiv Inbound federation can receive invite and reject when remote replies with a 500 | ||||
| fiv Inbound federation can receive invite and reject when remote is unreachable | ||||
| fiv Inbound federation rejects invites which are not signed by the sender | ||||
| fiv Inbound federation can receive invite rejections | ||||
| fiv Inbound federation rejects incorrectly-signed invite rejections | ||||
| fsl Inbound /v1/send_leave rejects leaves from other servers | ||||
| fst Inbound federation can get state for a room | ||||
| fst Inbound federation of state requires event_id as a mandatory paramater | ||||
| fst Inbound federation can get state_ids for a room | ||||
| fst Inbound federation of state_ids requires event_id as a mandatory paramater | ||||
| fst  Federation rejects inbound events where the prev_events cannot be found | ||||
| fst Room state at a rejected message event is the same as its predecessor | ||||
| fst Room state at a rejected state event is the same as its predecessor | ||||
| fst Outbound federation requests missing prev_events and then asks for /state_ids and resolves the state | ||||
| fst Federation handles empty auth_events in state_ids sanely | ||||
| fst Getting state checks the events requested belong to the room | ||||
| fst Getting state IDs checks the events requested belong to the room | ||||
| fst Should not be able to take over the room by pretending there is no PL event | ||||
| fpb Inbound federation can get public room list | ||||
| fed Outbound federation sends receipts | ||||
| fed Inbound federation rejects receipts from wrong remote | ||||
| fed Inbound federation ignores redactions from invalid servers room > v3 | ||||
| fed An event which redacts an event in a different room should be ignored | ||||
| fed An event which redacts itself should be ignored | ||||
| fed A pair of events which redact each other should be ignored | ||||
| fdk Local device key changes get to remote servers | ||||
| fdk Server correctly handles incoming m.device_list_update | ||||
| fdk Server correctly resyncs when client query keys and there is no remote cache | ||||
| fdk Server correctly resyncs when server leaves and rejoins a room | ||||
| fdk Local device key changes get to remote servers with correct prev_id | ||||
| fdk Device list doesn't change if remote server is down | ||||
| fdk If a device list update goes missing, the server resyncs on the next one | ||||
| fst Name/topic keys are correct | ||||
| fau Remote servers cannot set power levels in rooms without existing powerlevels | ||||
| fau Remote servers should reject attempts by non-creators to set the power levels | ||||
| fau Inbound federation rejects typing notifications from wrong remote | ||||
| fed Forward extremities remain so even after the next events are populated as outliers | ||||
| fau Banned servers cannot send events | ||||
| fau Banned servers cannot /make_join | ||||
| fau Banned servers cannot /send_join | ||||
| fau Banned servers cannot /make_leave | ||||
| fau Banned servers cannot /send_leave | ||||
| fau Banned servers cannot /invite | ||||
| fau Banned servers cannot get room state | ||||
| fau Banned servers cannot get room state ids | ||||
| fau Banned servers cannot backfill | ||||
| fau Banned servers cannot /event_auth | ||||
| fau Banned servers cannot get missing events | ||||
| fau Server correctly handles transactions that break edu limits | ||||
| fau Inbound federation correctly soft fails events | ||||
| fau Inbound federation accepts a second soft-failed event | ||||
| fau Inbound federation correctly handles soft failed events as extremities | ||||
| med Can upload with Unicode file name | ||||
| med Can download with Unicode file name locally | ||||
| f,med Can download with Unicode file name over federation | ||||
| med Alternative server names do not cause a routing loop | ||||
| med Can download specifying a different Unicode file name | ||||
| med Can upload without a file name | ||||
| med Can download without a file name locally | ||||
| f,med Can download without a file name over federation | ||||
| med Can upload with ASCII file name | ||||
| med Can download file 'ascii' | ||||
| med Can download file 'name with spaces' | ||||
| med Can download file 'name;with;semicolons' | ||||
| med Can download specifying a different ASCII file name | ||||
| med Can send image in room message | ||||
| med Can fetch images in room | ||||
| med POSTed media can be thumbnailed | ||||
| f,med Remote media can be thumbnailed | ||||
| med Test URL preview | ||||
| med Can read configuration endpoint | ||||
| nsp Can quarantine media in rooms | ||||
| udr User appears in user directory | ||||
| udr User in private room doesn't appear in user directory | ||||
| udr User joining then leaving public room appears and dissappears from directory | ||||
| udr Users appear/disappear from directory when join_rules are changed | ||||
| udr Users appear/disappear from directory when history_visibility are changed | ||||
| udr Users stay in directory when join_rules are changed but history_visibility is world_readable | ||||
| f,udr User in remote room doesn't appear in user directory after server left room | ||||
| udr User directory correctly update on display name change | ||||
| udr User in shared private room does appear in user directory | ||||
| udr User in shared private room does appear in user directory until leave | ||||
| udr User in dir while user still shares private rooms | ||||
| nsp Create group | ||||
| nsp Add group rooms | ||||
| nsp Remove group rooms | ||||
| nsp Get local group profile | ||||
| nsp Get local group users | ||||
| nsp Add/remove local group rooms | ||||
| nsp Get local group summary | ||||
| nsp Get remote group profile | ||||
| nsp Get remote group users | ||||
| nsp Add/remove remote group rooms | ||||
| nsp Get remote group summary | ||||
| nsp Add local group users | ||||
| nsp Remove self from local group | ||||
| nsp Remove other from local group | ||||
| nsp Add remote group users | ||||
| nsp Remove self from remote group | ||||
| nsp Listing invited users of a remote group when not a member returns a 403 | ||||
| nsp Add group category | ||||
| nsp Remove group category | ||||
| nsp Get group categories | ||||
| nsp Add group role | ||||
| nsp Remove group role | ||||
| nsp Get group roles | ||||
| nsp Add room to group summary | ||||
| nsp Adding room to group summary keeps room_id when fetching rooms in group | ||||
| nsp Adding multiple rooms to group summary have correct order | ||||
| nsp Remove room from group summary | ||||
| nsp Add room to group summary with category | ||||
| nsp Remove room from group summary with category | ||||
| nsp Add user to group summary | ||||
| nsp Adding multiple users to group summary have correct order | ||||
| nsp Remove user from group summary | ||||
| nsp Add user to group summary with role | ||||
| nsp Remove user from group summary with role | ||||
| nsp Local group invites come down sync | ||||
| nsp Group creator sees group in sync | ||||
| nsp Group creator sees group in initial sync | ||||
| nsp Get/set local group publicity | ||||
| nsp Bulk get group publicity | ||||
| nsp Joinability comes down summary | ||||
| nsp Set group joinable and join it | ||||
| nsp Group is not joinable by default | ||||
| nsp Group is joinable over federation | ||||
| nsp Room is transitioned on local and remote groups upon room upgrade | ||||
| 3pd Can bind 3PID via home server | ||||
| 3pd Can bind and unbind 3PID via homeserver | ||||
| 3pd Can unbind 3PID via homeserver when bound out of band | ||||
| 3pd 3PIDs are unbound after account deactivation | ||||
| 3pd Can bind and unbind 3PID via /unbind by specifying the identity server | ||||
| 3pd Can bind and unbind 3PID via /unbind without specifying the identity server | ||||
| app AS can create a user | ||||
| app AS can create a user with an underscore | ||||
| app AS can create a user with inhibit_login | ||||
| app AS cannot create users outside its own namespace | ||||
| app Regular users cannot register within the AS namespace | ||||
| app AS can make room aliases | ||||
| app Regular users cannot create room aliases within the AS namespace | ||||
| app AS-ghosted users can use rooms via AS | ||||
| app AS-ghosted users can use rooms themselves | ||||
| app Ghost user must register before joining room | ||||
| app AS can set avatar for ghosted users | ||||
| app AS can set displayname for ghosted users | ||||
| app AS can't set displayname for random users | ||||
| app Inviting an AS-hosted user asks the AS server | ||||
| app Accesing an AS-hosted room alias asks the AS server | ||||
| app Events in rooms with AS-hosted room aliases are sent to AS server | ||||
| app AS user (not ghost) can join room without registering | ||||
| app AS user (not ghost) can join room without registering, with user_id query param | ||||
| app HS provides query metadata | ||||
| app HS can provide query metadata on a single protocol | ||||
| app HS will proxy request for 3PU mapping | ||||
| app HS will proxy request for 3PL mapping | ||||
| app AS can publish rooms in their own list | ||||
| app AS and main public room lists are separate | ||||
| app AS can deactivate a user | ||||
| psh Test that a message is pushed | ||||
| psh Invites are pushed | ||||
| psh Rooms with names are correctly named in pushed | ||||
| psh Rooms with canonical alias are correctly named in pushed | ||||
| psh Rooms with many users are correctly pushed | ||||
| psh Don't get pushed for rooms you've muted | ||||
| psh Rejected events are not pushed | ||||
| psh Can add global push rule for room | ||||
| psh Can add global push rule for sender | ||||
| psh Can add global push rule for content | ||||
| psh Can add global push rule for override | ||||
| psh Can add global push rule for underride | ||||
| psh Can add global push rule for content | ||||
| psh New rules appear before old rules by default | ||||
| psh Can add global push rule before an existing rule | ||||
| psh Can add global push rule after an existing rule | ||||
| psh Can delete a push rule | ||||
| psh Can disable a push rule | ||||
| psh Adding the same push rule twice is idempotent | ||||
| psh Messages that notify from another user increment unread notification count | ||||
| psh Messages that highlight from another user increment unread highlight count | ||||
| psh Can change the actions of default rules | ||||
| psh Changing the actions of an unknown default rule fails with 404 | ||||
| psh Can change the actions of a user specified rule | ||||
| psh Changing the actions of an unknown rule fails with 404 | ||||
| psh Can fetch a user's pushers | ||||
| psh Push rules come down in an initial /sync | ||||
| psh Adding a push rule wakes up an incremental /sync | ||||
| psh Disabling a push rule wakes up an incremental /sync | ||||
| psh Enabling a push rule wakes up an incremental /sync | ||||
| psh Setting actions for a push rule wakes up an incremental /sync | ||||
| psh Can enable/disable default rules | ||||
| psh Enabling an unknown default rule fails with 404 | ||||
| psh Test that rejected pushers are removed. | ||||
| psh Notifications can be viewed with GET /notifications | ||||
| psh Trying to add push rule with no scope fails with 400 | ||||
| psh Trying to add push rule with invalid scope fails with 400 | ||||
| psh Trying to add push rule with missing template fails with 400 | ||||
| psh Trying to add push rule with missing rule_id fails with 400 | ||||
| psh Trying to add push rule with empty rule_id fails with 400 | ||||
| psh Trying to add push rule with invalid template fails with 400 | ||||
| psh Trying to add push rule with rule_id with slashes fails with 400 | ||||
| psh Trying to add push rule with override rule without conditions fails with 400 | ||||
| psh Trying to add push rule with underride rule without conditions fails with 400 | ||||
| psh Trying to add push rule with condition without kind fails with 400 | ||||
| psh Trying to add push rule with content rule without pattern fails with 400 | ||||
| psh Trying to add push rule with no actions fails with 400 | ||||
| psh Trying to add push rule with invalid action fails with 400 | ||||
| psh Trying to add push rule with invalid attr fails with 400 | ||||
| psh Trying to add push rule with invalid value for enabled fails with 400 | ||||
| psh Trying to get push rules with no trailing slash fails with 400 | ||||
| psh Trying to get push rules with scope without trailing slash fails with 400 | ||||
| psh Trying to get push rules with template without tailing slash fails with 400 | ||||
| psh Trying to get push rules with unknown scope fails with 400 | ||||
| psh Trying to get push rules with unknown template fails with 400 | ||||
| psh Trying to get push rules with unknown attribute fails with 400 | ||||
| psh Trying to get push rules with unknown rule_id fails with 404 | ||||
| v1s GET /initialSync with non-numeric 'limit' | ||||
| v1s GET /events with non-numeric 'limit' | ||||
| v1s GET /events with negative 'limit' | ||||
| v1s GET /events with non-numeric 'timeout' | ||||
| ath Event size limits | ||||
| syn Check creating invalid filters returns 4xx | ||||
| f,pre New federated private chats get full presence information (SYN-115) | ||||
| pre Left room members do not cause problems for presence | ||||
| crm Rooms can be created with an initial invite list (SYN-205) | ||||
| typ Typing notifications don't leak | ||||
| ban Non-present room members cannot ban others | ||||
| psh Getting push rules doesn't corrupt the cache SYN-390 | ||||
| inv Test that we can be reinvited to a room we created | ||||
| syn Multiple calls to /sync should not cause 500 errors | ||||
| gst Guest user can call /events on another world_readable room (SYN-606) | ||||
| gst Real user can call /events on another world_readable room (SYN-606) | ||||
| gst Events come down the correct room | ||||
| pub Asking for a remote rooms list, but supplying the local server's name, returns the local rooms list | ||||
| std Can send a to-device message to two users which both receive it using /sync | ||||
							
								
								
									
										260
									
								
								sytest/are-we-synapse-yet.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										260
									
								
								sytest/are-we-synapse-yet.py
									
									
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,260 @@ | |||
| #!/usr/bin/env python3 | ||||
| 
 | ||||
| from __future__ import division | ||||
| import argparse | ||||
| import re | ||||
| import sys | ||||
| 
 | ||||
| # Usage: $ ./are-we-synapse-yet.py [-v] results.tap | ||||
| # This script scans a results.tap file from Dendrite's CI process and spits out | ||||
| # a rating of how close we are to Synapse parity, based purely on SyTests. | ||||
| # The main complexity is grouping tests sensibly into features like 'Registration' | ||||
| # and 'Federation'. Then it just checks the ones which are passing and calculates | ||||
| # percentages for each group. Produces results like: | ||||
| # | ||||
| # Client-Server APIs: 29% (196/666 tests) | ||||
| # ------------------- | ||||
| #   Registration             :  62% (20/32 tests) | ||||
| #   Login                    :   7% (1/15 tests) | ||||
| #   V1 CS APIs               :  10% (3/30 tests) | ||||
| #   ... | ||||
| # | ||||
| # or in verbose mode: | ||||
| # | ||||
| # Client-Server APIs: 29% (196/666 tests) | ||||
| # ------------------- | ||||
| #  Registration             :  62% (20/32 tests) | ||||
| #    ✓ GET /register yields a set of flows | ||||
| #    ✓ POST /register can create a user | ||||
| #    ✓ POST /register downcases capitals in usernames | ||||
| #    ... | ||||
| # | ||||
| # You can also tack `-v` on to see exactly which tests each category falls under. | ||||
| 
 | ||||
| test_mappings = { | ||||
|     "nsp": "Non-Spec API", | ||||
|     "f": "Federation", # flag to mark test involves federation | ||||
| 
 | ||||
|     "federation_apis": { | ||||
|         "fky": "Key API", | ||||
|         "fsj": "send_join API", | ||||
|         "fmj": "make_join API", | ||||
|         "fsl": "send_leave API", | ||||
|         "fiv": "Invite API", | ||||
|         "fqu": "Query API", | ||||
|         "frv": "room versions", | ||||
|         "fau": "Auth", | ||||
|         "fbk": "Backfill API", | ||||
|         "fme": "get_missing_events API", | ||||
|         "fst": "State APIs", | ||||
|         "fpb": "Public Room API", | ||||
|         "fdk": "Device Key APIs", | ||||
|         "fed": "Federation API", | ||||
|     }, | ||||
| 
 | ||||
|     "client_apis": { | ||||
|         "reg": "Registration", | ||||
|         "log": "Login", | ||||
|         "lox": "Logout", | ||||
|         "v1s": "V1 CS APIs", | ||||
|         "csa": "Misc CS APIs", | ||||
|         "pro": "Profile", | ||||
|         "dev": "Devices", | ||||
|         "dvk": "Device Keys", | ||||
|         "pre": "Presence", | ||||
|         "crm": "Create Room", | ||||
|         "syn": "Sync API", | ||||
|         "rmv": "Room Versions", | ||||
|         "rst": "Room State APIs", | ||||
|         "pub": "Public Room APIs", | ||||
|         "mem": "Room Membership", | ||||
|         "ali": "Room Aliases", | ||||
|         "jon": "Joining Rooms", | ||||
|         "lev": "Leaving Rooms", | ||||
|         "inv": "Inviting users to Rooms", | ||||
|         "ban": "Banning users", | ||||
|         "snd": "Sending events", | ||||
|         "get": "Getting events for Rooms", | ||||
|         "rct": "Receipts", | ||||
|         "red": "Read markers", | ||||
|         "med": "Media APIs", | ||||
|         "cap": "Capabilities API", | ||||
|         "typ": "Typing API", | ||||
|         "psh": "Push APIs", | ||||
|         "acc": "Account APIs", | ||||
|         "eph": "Ephemeral Events", | ||||
|         "plv": "Power Levels", | ||||
|         "xxx": "Redaction", | ||||
|         "3pd": "Third-Party ID APIs", | ||||
|         "gst": "Guest APIs", | ||||
|         "ath": "Room Auth", | ||||
|         "fgt": "Forget APIs", | ||||
|         "ctx": "Context APIs", | ||||
|         "upg": "Room Upgrade APIs", | ||||
|         "tag": "Tagging APIs", | ||||
|         "sch": "Search APIs", | ||||
|         "oid": "OpenID API", | ||||
|         "std": "Send-to-Device APIs", | ||||
|         "adm": "Server Admin API", | ||||
|         "ign": "Ignore Users", | ||||
|         "udr": "User Directory APIs", | ||||
|         "app": "Application Services API", | ||||
|     }, | ||||
| } | ||||
| 
 | ||||
| # optional 'not ' with test number then anything but '#' | ||||
| re_testname = re.compile(r"^(not )?ok [0-9]+ ([^#]+)") | ||||
| 
 | ||||
| # Parses lines like the following: | ||||
| # | ||||
| # SUCCESS:     ok 3 POST /register downcases capitals in usernames | ||||
| # FAIL:        not ok 54 (expected fail) POST /createRoom creates a room with the given version | ||||
| # SKIP:        ok 821 Multiple calls to /sync should not cause 500 errors # skip lack of can_post_room_receipts | ||||
| # EXPECT FAIL: not ok 822 (expected fail) Guest user can call /events on another world_readable room (SYN-606) # TODO expected fail | ||||
| # | ||||
| # Only SUCCESS lines are treated as success, the rest are not implemented. | ||||
| # | ||||
| # Returns a dict like: | ||||
| # { name: "...", ok: True } | ||||
| def parse_test_line(line): | ||||
|     if not line.startswith("ok ") and not line.startswith("not ok "): | ||||
|         return | ||||
|     re_match = re_testname.match(line) | ||||
|     test_name = re_match.groups()[1].replace("(expected fail) ", "").strip() | ||||
|     test_pass = False | ||||
|     if line.startswith("ok ") and not "# skip " in line: | ||||
|         test_pass = True | ||||
|     return { | ||||
|         "name": test_name, | ||||
|         "ok": test_pass, | ||||
|     } | ||||
| 
 | ||||
| # Prints the stats for a complete section. | ||||
| #   header_name => "Client-Server APIs" | ||||
| #   gid_to_tests => { gid: { <name>: True|False }} | ||||
| #   gid_to_name  => { gid: "Group Name" } | ||||
| #   verbose => True|False | ||||
| # Produces: | ||||
| # Client-Server APIs: 29% (196/666 tests) | ||||
| # ------------------- | ||||
| #   Registration             :  62% (20/32 tests) | ||||
| #   Login                    :   7% (1/15 tests) | ||||
| #   V1 CS APIs               :  10% (3/30 tests) | ||||
| #   ... | ||||
| # or in verbose mode: | ||||
| # Client-Server APIs: 29% (196/666 tests) | ||||
| # ------------------- | ||||
| #  Registration             :  62% (20/32 tests) | ||||
| #    ✓ GET /register yields a set of flows | ||||
| #    ✓ POST /register can create a user | ||||
| #    ✓ POST /register downcases capitals in usernames | ||||
| #    ... | ||||
| def print_stats(header_name, gid_to_tests, gid_to_name, verbose): | ||||
|     subsections = [] # Registration: 100% (13/13 tests) | ||||
|     subsection_test_names = {} # 'subsection name': ["✓ Test 1", "✓ Test 2", "× Test 3"] | ||||
|     total_passing = 0 | ||||
|     total_tests = 0 | ||||
|     for gid, tests in gid_to_tests.items(): | ||||
|         group_total = len(tests) | ||||
|         group_passing = 0 | ||||
|         test_names_and_marks = [] | ||||
|         for name, passing in tests.items(): | ||||
|             if passing: | ||||
|                 group_passing += 1 | ||||
|             test_names_and_marks.append(f"{'✓' if passing else '×'} {name}") | ||||
| 
 | ||||
|         total_tests += group_total | ||||
|         total_passing += group_passing | ||||
|         pct = "{0:.0f}%".format(group_passing/group_total * 100) | ||||
|         line = "%s: %s (%d/%d tests)" % (gid_to_name[gid].ljust(25, ' '), pct.rjust(4, ' '), group_passing, group_total) | ||||
|         subsections.append(line) | ||||
|         subsection_test_names[line] = test_names_and_marks | ||||
| 
 | ||||
|     pct = "{0:.0f}%".format(total_passing/total_tests * 100) | ||||
|     print("%s: %s (%d/%d tests)" % (header_name, pct, total_passing, total_tests)) | ||||
|     print("-" * (len(header_name)+1)) | ||||
|     for line in subsections: | ||||
|         print("  %s" % (line,)) | ||||
|         if verbose: | ||||
|             for test_name_and_pass_mark in subsection_test_names[line]: | ||||
|                 print("    %s" % (test_name_and_pass_mark,)) | ||||
|             print("") | ||||
|     print("") | ||||
| 
 | ||||
| def main(results_tap_path, verbose): | ||||
|     # Load up test mappings | ||||
|     test_name_to_group_id = {} | ||||
|     fed_tests = set() | ||||
|     client_tests = set() | ||||
|     groupless_tests = set() | ||||
|     with open("./are-we-synapse-yet.list", "r") as f: | ||||
|         for line in f.readlines(): | ||||
|             test_name = " ".join(line.split(" ")[1:]).strip() | ||||
|             groups = line.split(" ")[0].split(",") | ||||
|             for gid in groups: | ||||
|                 if gid == "f" or gid in test_mappings["federation_apis"]: | ||||
|                     fed_tests.add(test_name) | ||||
|                 else: | ||||
|                     client_tests.add(test_name) | ||||
|                 if gid == "f": | ||||
|                     continue # we expect another group ID | ||||
|                 test_name_to_group_id[test_name] = gid | ||||
| 
 | ||||
|     # parse results.tap | ||||
|     summary = { | ||||
|         "client": { | ||||
|             # gid: { | ||||
|             #   test_name: OK | ||||
|             # } | ||||
|         }, | ||||
|         "federation": { | ||||
|             # gid: { | ||||
|             #   test_name: OK | ||||
|             # } | ||||
|         }, | ||||
|         "nonspec": { | ||||
|             "nsp": {} | ||||
|         }, | ||||
|     } | ||||
|     with open(results_tap_path, "r") as f: | ||||
|         for line in f.readlines(): | ||||
|             test_result = parse_test_line(line) | ||||
|             if not test_result: | ||||
|                 continue | ||||
|             name = test_result["name"] | ||||
|             group_id = test_name_to_group_id.get(name) | ||||
|             if not group_id: | ||||
|                 groupless_tests.add(name) | ||||
|                 # raise Exception("The test '%s' doesn't have a group" % (name,)) | ||||
|             if group_id == "nsp": | ||||
|                 summary["nonspec"]["nsp"][name] = test_result["ok"] | ||||
|             elif group_id in test_mappings["federation_apis"]: | ||||
|                 group = summary["federation"].get(group_id, {}) | ||||
|                 group[name] = test_result["ok"] | ||||
|                 summary["federation"][group_id] = group | ||||
|             elif group_id in test_mappings["client_apis"]: | ||||
|                 group = summary["client"].get(group_id, {}) | ||||
|                 group[name] = test_result["ok"] | ||||
|                 summary["client"][group_id] = group | ||||
| 
 | ||||
|     print("Are We Synapse Yet?") | ||||
|     print("===================") | ||||
|     print("") | ||||
|     print_stats("Non-Spec APIs", summary["nonspec"], test_mappings, verbose) | ||||
|     print_stats("Client-Server APIs", summary["client"], test_mappings["client_apis"], verbose) | ||||
|     print_stats("Federation APIs", summary["federation"], test_mappings["federation_apis"], verbose) | ||||
|     if verbose: | ||||
|         print("The following tests don't have a group:") | ||||
|         for name in groupless_tests: | ||||
|             print("  %s" % (name,)) | ||||
|     else: | ||||
|         print("%d tests don't have a group" % len(groupless_tests)) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     parser = argparse.ArgumentParser() | ||||
|     parser.add_argument("tap_file", help="path to results.tap") | ||||
|     parser.add_argument("-v", action="store_true", help="show individual test names in output") | ||||
|     args = parser.parse_args() | ||||
|     main(args.tap_file, args.v) | ||||
							
								
								
									
										105
									
								
								sytest/show-expected-fail-tests.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										105
									
								
								sytest/show-expected-fail-tests.sh
									
									
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,105 @@ | |||
| #! /bin/bash | ||||
| # | ||||
| # Parses a results.tap file from SyTest output and a file containing test names (a test whitelist) | ||||
| # and checks whether a test name that exists in the whitelist (that should pass), failed or not. | ||||
| # | ||||
| # An optional blacklist file can be added, also containing test names, where if a test name is | ||||
| # present, the script will not error even if the test is in the whitelist file and failed | ||||
| # | ||||
| # For each of these files, lines starting with '#' are ignored. | ||||
| # | ||||
| # Usage ./show-expected-fail-tests.sh results.tap whitelist [blacklist] | ||||
| 
 | ||||
| results_file=$1 | ||||
| whitelist_file=$2 | ||||
| blacklist_file=$3 | ||||
| 
 | ||||
| fail_build=0 | ||||
| 
 | ||||
| if [ $# -lt 2 ]; then | ||||
| 	echo "Usage: $0 results.tap whitelist [blacklist]" | ||||
| 	exit 1 | ||||
| fi | ||||
| 
 | ||||
| if [ ! -f "$results_file" ]; then | ||||
| 	echo "ERROR: Specified results file '${results_file}' doesn't exist." | ||||
| 	fail_build=1 | ||||
| fi | ||||
| 
 | ||||
| if [ ! -f "$whitelist_file" ]; then | ||||
| 	echo "ERROR: Specified test whitelist '${whitelist_file}' doesn't exist." | ||||
| 	fail_build=1 | ||||
| fi | ||||
| 
 | ||||
| blacklisted_tests=() | ||||
| 
 | ||||
| # Check if a blacklist file was provided | ||||
| if [ $# -eq 3 ]; then | ||||
| 	# Read test blacklist file | ||||
| 	if [ ! -f "$blacklist_file" ]; then | ||||
| 		echo "ERROR: Specified test blacklist file '${blacklist_file}' doesn't exist." | ||||
| 		fail_build=1 | ||||
| 	fi | ||||
| 
 | ||||
| 	# Read each line, ignoring those that start with '#' | ||||
| 	blacklisted_tests="" | ||||
| 	search_non_comments=$(grep -v '^#' ${blacklist_file}) | ||||
| 	while read -r line ; do | ||||
| 		# Record the blacklisted test name | ||||
| 		blacklisted_tests+=("${line}") | ||||
| 	done <<< "${search_non_comments}"  # This allows us to edit blacklisted_tests in the while loop | ||||
| fi | ||||
| 
 | ||||
| [ "$fail_build" = 0 ] || exit 1 | ||||
| 
 | ||||
| passed_but_expected_fail=$(grep ' # TODO passed but expected fail' ${results_file} | sed -E 's/^ok [0-9]+ (\(expected fail\) )?//' | sed -E 's/( \([0-9]+ subtests\))? # TODO passed but expected fail$//') | ||||
| tests_to_add="" | ||||
| already_in_whitelist="" | ||||
| 
 | ||||
| while read -r test_name; do | ||||
| 	# Ignore empty lines | ||||
| 	[ "${test_name}" = "" ] && continue | ||||
| 
 | ||||
| 	grep "^${test_name}" "${whitelist_file}" > /dev/null 2>&1 | ||||
| 	if [ "$?" != "0" ]; then | ||||
| 		# Check if this test name is blacklisted | ||||
| 		if printf '%s\n' "${blacklisted_tests[@]}" | grep -q -P "^${test_name}$"; then | ||||
| 			# Don't notify about this test | ||||
| 			continue | ||||
| 		fi | ||||
| 
 | ||||
| 		# Append this test_name to the existing list | ||||
| 		tests_to_add="${tests_to_add}${test_name}\n" | ||||
| 		fail_build=1 | ||||
| 	else | ||||
| 		already_in_whitelist="${already_in_whitelist}${test_name}\n" | ||||
| 	fi | ||||
| done <<< "${passed_but_expected_fail}" | ||||
| 
 | ||||
| # TODO: Check that the same test doesn't exist in both the whitelist and blacklist | ||||
| # TODO: Check that the same test doesn't appear twice in the whitelist|blacklist | ||||
| 
 | ||||
| # Trim test output strings | ||||
| tests_to_add=$(IFS=$'\n' echo "${tests_to_add[*]%%'\n'}") | ||||
| already_in_whitelist=$(IFS=$'\n' echo "${already_in_whitelist[*]%%'\n'}") | ||||
| 
 | ||||
| # Format output with markdown for buildkite annotation rendering purposes | ||||
| if [ -n "${tests_to_add}" ] && [ -n "${already_in_whitelist}" ]; then | ||||
| 	echo "### 📜 SyTest Whitelist Maintenance" | ||||
| fi | ||||
| 
 | ||||
| if [ -n "${tests_to_add}" ]; then | ||||
| 	echo "**ERROR**: The following tests passed but are not present in \`$2\`. Please append them to the file:" | ||||
|     echo "\`\`\`" | ||||
|     echo -e "${tests_to_add}" | ||||
|     echo "\`\`\`" | ||||
| fi | ||||
| 
 | ||||
| if [ -n "${already_in_whitelist}" ]; then | ||||
| 	echo "**WARN**: Tests in the whitelist still marked as **expected fail**:" | ||||
|     echo "\`\`\`" | ||||
|     echo -e "${already_in_whitelist}" | ||||
|     echo "\`\`\`" | ||||
| fi | ||||
| 
 | ||||
| exit ${fail_build} | ||||
							
								
								
									
										0
									
								
								sytest/sytest-blacklist
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								sytest/sytest-blacklist
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										85
									
								
								sytest/sytest-whitelist
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								sytest/sytest-whitelist
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,85 @@ | |||
| # Register endpoints implemented | ||||
| GET /register yields a set of flows | ||||
| POST /register can create a user | ||||
| POST /register downcases capitals in usernames | ||||
| POST /register rejects registration of usernames with '!' | ||||
| POST /register rejects registration of usernames with '"' | ||||
| POST /register rejects registration of usernames with ':' | ||||
| POST /register rejects registration of usernames with '?' | ||||
| POST /register rejects registration of usernames with '\' | ||||
| POST /register rejects registration of usernames with '@' | ||||
| POST /register rejects registration of usernames with '[' | ||||
| POST /register rejects registration of usernames with ']' | ||||
| POST /register rejects registration of usernames with '{' | ||||
| POST /register rejects registration of usernames with '|' | ||||
| POST /register rejects registration of usernames with '}' | ||||
| POST /register rejects registration of usernames with '£' | ||||
| POST /register rejects registration of usernames with 'é' | ||||
| POST /register rejects registration of usernames with '\n' | ||||
| POST /register rejects registration of usernames with ''' | ||||
| # Login endpoints implemented | ||||
| GET /login yields a set of flows | ||||
| POST /login can log in as a user | ||||
| POST /login returns the same device_id as that in the request | ||||
| POST /login can log in as a user with just the local part of the id | ||||
| POST /login as non-existing user is rejected | ||||
| POST /login wrong password is rejected | ||||
| # Room creation endpoints implemented | ||||
| POST /createRoom makes a public room | ||||
| POST /createRoom makes a private room | ||||
| POST /createRoom makes a private room with invites | ||||
| POST /createRoom makes a room with a name | ||||
| POST /createRoom makes a room with a topic | ||||
| Can /sync newly created room | ||||
| GET /rooms/:room_id/state/m.room.member/:user_id fetches my membership | ||||
| GET /rooms/:room_id/state/m.room.power_levels fetches powerlevels | ||||
| POST /join/:room_alias can join a room | ||||
| POST /join/:room_id can join a room | ||||
| POST /join/:room_id can join a room with custom content | ||||
| POST /join/:room_alias can join a room with custom content | ||||
| POST /rooms/:room_id/join can join a room | ||||
| POST /rooms/:room_id/leave can leave a room | ||||
| POST /rooms/:room_id/invite can send an invite | ||||
| POST /rooms/:room_id/ban can ban a user | ||||
| POST /rooms/:room_id/send/:event_type sends a message | ||||
| PUT /rooms/:room_id/send/:event_type/:txn_id sends a message | ||||
| PUT /rooms/:room_id/send/:event_type/:txn_id deduplicates the same txn id | ||||
| GET /rooms/:room_id/state/m.room.power_levels can fetch levels | ||||
| PUT /rooms/:room_id/state/m.room.power_levels can set levels | ||||
| PUT power_levels should not explode if the old power levels were empty | ||||
| Both GET and PUT work | ||||
| POST /rooms/:room_id/read_markers can create read marker | ||||
| User signups are forbidden from starting with '_' | ||||
| Request to logout with invalid an access token is rejected | ||||
| Request to logout without an access token is rejected | ||||
| Room creation reports m.room.create to myself | ||||
| Room creation reports m.room.member to myself | ||||
| Version responds 200 OK with valid structure | ||||
| PUT /profile/:user_id/displayname sets my name | ||||
| GET /profile/:user_id/displayname publicly accessible | ||||
| GET /device/{deviceId} gives a 404 for unknown devices | ||||
| PUT /device/{deviceId} gives a 404 for unknown devices | ||||
| After deactivating account, can't log in with an email | ||||
| Can create filter | ||||
| Should reject keys claiming to belong to a different user | ||||
| Can add account data | ||||
| Checking local federation server | ||||
| Alternative server names do not cause a routing loop | ||||
| Can read configuration endpoint | ||||
| AS cannot create users outside its own namespace | ||||
| Changing the actions of an unknown default rule fails with 404 | ||||
| Changing the actions of an unknown rule fails with 404 | ||||
| Trying to add push rule with invalid scope fails with 400 | ||||
| Trying to add push rule with invalid template fails with 400 | ||||
| Trying to add push rule with rule_id with slashes fails with 400 | ||||
| Trying to add push rule with override rule without conditions fails with 400 | ||||
| Trying to add push rule with underride rule without conditions fails with 400 | ||||
| Trying to add push rule with condition without kind fails with 400 | ||||
| Trying to add push rule with content rule without pattern fails with 400 | ||||
| Trying to add push rule with no actions fails with 400 | ||||
| Trying to add push rule with invalid action fails with 400 | ||||
| Trying to get push rules with unknown rule_id fails with 404 | ||||
| GET /events with non-numeric 'limit' | ||||
| GET /events with negative 'limit' | ||||
| GET /events with non-numeric 'timeout' | ||||
| Getting push rules doesn't corrupt the cache SYN-390 | ||||
		Loading…
	
		Reference in a new issue