You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

667 lines
22 KiB

  1. """Test module for KeycloakUMA."""
  2. import re
  3. from inspect import iscoroutinefunction, signature
  4. import pytest
  5. from keycloak import KeycloakAdmin, KeycloakOpenIDConnection, KeycloakUMA
  6. from keycloak.exceptions import (
  7. KeycloakDeleteError,
  8. KeycloakGetError,
  9. KeycloakPostError,
  10. KeycloakPutError,
  11. )
  12. from keycloak.uma_permissions import UMAPermission
  13. def test_keycloak_uma_init(oid_connection_with_authz: KeycloakOpenIDConnection) -> None:
  14. """
  15. Test KeycloakUMA's init method.
  16. :param oid_connection_with_authz: Keycloak OpenID connection manager with preconfigured authz
  17. :type oid_connection_with_authz: KeycloakOpenIDConnection
  18. """
  19. connection = oid_connection_with_authz
  20. uma = KeycloakUMA(connection=connection)
  21. assert isinstance(uma.connection, KeycloakOpenIDConnection)
  22. # should initially be empty
  23. assert uma._well_known is None
  24. assert uma.uma_well_known
  25. # should be cached after first reference
  26. assert uma._well_known is not None
  27. def test_uma_well_known(uma: KeycloakUMA) -> None:
  28. """
  29. Test the well_known method.
  30. :param uma: Keycloak UMA client
  31. :type uma: KeycloakUMA
  32. """
  33. res = uma.uma_well_known
  34. assert res is not None
  35. assert res != {}
  36. for key in ["resource_registration_endpoint"]:
  37. assert key in res
  38. def test_uma_resource_sets(uma: KeycloakUMA) -> None:
  39. """
  40. Test resource sets.
  41. :param uma: Keycloak UMA client
  42. :type uma: KeycloakUMA
  43. """
  44. # Check that only the default resource is present
  45. resource_sets = uma.resource_set_list()
  46. resource_set_list = list(resource_sets)
  47. assert len(resource_set_list) == 1, resource_set_list
  48. assert resource_set_list[0]["name"] == "Default Resource", resource_set_list[0]["name"]
  49. # Test query for resource sets
  50. resource_set_list_ids = uma.resource_set_list_ids()
  51. assert len(resource_set_list_ids) == 1
  52. resource_set_list_ids2 = uma.resource_set_list_ids(name="Default")
  53. assert resource_set_list_ids2 == resource_set_list_ids
  54. resource_set_list_ids2 = uma.resource_set_list_ids(name="Default Resource")
  55. assert resource_set_list_ids2 == resource_set_list_ids
  56. resource_set_list_ids = uma.resource_set_list_ids(name="Default", exact_name=True)
  57. assert len(resource_set_list_ids) == 0
  58. resource_set_list_ids = uma.resource_set_list_ids(first=1)
  59. assert len(resource_set_list_ids) == 0
  60. resource_set_list_ids = uma.resource_set_list_ids(scope="Invalid")
  61. assert len(resource_set_list_ids) == 0
  62. resource_set_list_ids = uma.resource_set_list_ids(owner="Invalid")
  63. assert len(resource_set_list_ids) == 0
  64. resource_set_list_ids = uma.resource_set_list_ids(resource_type="Invalid")
  65. assert len(resource_set_list_ids) == 0
  66. resource_set_list_ids = uma.resource_set_list_ids(name="Invalid")
  67. assert len(resource_set_list_ids) == 0
  68. resource_set_list_ids = uma.resource_set_list_ids(uri="Invalid")
  69. assert len(resource_set_list_ids) == 0
  70. resource_set_list_ids = uma.resource_set_list_ids(maximum=0)
  71. assert len(resource_set_list_ids) == 0
  72. # Test create resource set
  73. resource_to_create = {
  74. "name": "mytest",
  75. "scopes": ["test:read", "test:write"],
  76. "type": "urn:test",
  77. "uris": ["/some_resources/*"],
  78. }
  79. created_resource = uma.resource_set_create(resource_to_create)
  80. assert created_resource
  81. assert created_resource["_id"], created_resource
  82. assert set(resource_to_create).issubset(set(created_resource)), created_resource
  83. # Test getting resource with wildcard
  84. # Without matchingUri query option
  85. resource_set_list_ids = uma.resource_set_list_ids(uri="/some_resources/resource")
  86. assert len(resource_set_list_ids) == 0
  87. # With matchingUri query option
  88. resource_set_list_ids = uma.resource_set_list_ids(
  89. uri="/some_resources/resource",
  90. matchingUri=True,
  91. )
  92. assert len(resource_set_list_ids) == 1
  93. # Test create the same resource set
  94. with pytest.raises(KeycloakPostError) as err:
  95. uma.resource_set_create(resource_to_create)
  96. assert err.match(
  97. re.escape(
  98. '409: b\'{"error":"invalid_request","error_description":'
  99. '"Resource with name [mytest] already exists."}\'',
  100. ),
  101. )
  102. # Test get resource set
  103. latest_resource = uma.resource_set_read(created_resource["_id"])
  104. assert latest_resource["name"] == created_resource["name"]
  105. # Test update resource set
  106. latest_resource["name"] = "New Resource Name"
  107. res = uma.resource_set_update(created_resource["_id"], latest_resource)
  108. assert res == {}, res
  109. updated_resource = uma.resource_set_read(created_resource["_id"])
  110. assert updated_resource["name"] == "New Resource Name"
  111. # Test update resource set fail
  112. with pytest.raises(KeycloakPutError) as err:
  113. uma.resource_set_update(resource_id=created_resource["_id"], payload={"wrong": "payload"})
  114. assert err.match("Unrecognized field")
  115. # Test delete resource set
  116. res = uma.resource_set_delete(resource_id=created_resource["_id"])
  117. assert res == {}, res
  118. with pytest.raises(KeycloakGetError) as err:
  119. uma.resource_set_read(created_resource["_id"])
  120. err.match("404: b''")
  121. # Test delete fail
  122. with pytest.raises(KeycloakDeleteError) as err:
  123. uma.resource_set_delete(resource_id=created_resource["_id"])
  124. assert err.match("404: b''")
  125. def test_uma_policy(uma: KeycloakUMA, admin: KeycloakAdmin) -> None:
  126. """
  127. Test policies.
  128. :param uma: Keycloak UMA client
  129. :type uma: KeycloakUMA
  130. :param admin: Keycloak Admin client
  131. :type admin: KeycloakAdmin
  132. """
  133. # Create some required test data
  134. resource_to_create = {
  135. "name": "mytest",
  136. "scopes": ["test:read", "test:write"],
  137. "type": "urn:test",
  138. "ownerManagedAccess": True,
  139. }
  140. created_resource = uma.resource_set_create(resource_to_create)
  141. group_id = admin.create_group({"name": "UMAPolicyGroup"})
  142. role_id = admin.create_realm_role(payload={"name": "roleUMAPolicy"})
  143. other_client_id = admin.create_client({"name": "UMAOtherClient"})
  144. client = admin.get_client(other_client_id)
  145. resource_id = created_resource["_id"]
  146. # Create a role policy
  147. policy_to_create = {
  148. "name": "TestPolicyRole",
  149. "description": "Test resource policy description",
  150. "scopes": ["test:read", "test:write"],
  151. "roles": ["roleUMAPolicy"],
  152. }
  153. policy = uma.policy_resource_create(resource_id=resource_id, payload=policy_to_create)
  154. assert policy
  155. # Create a client policy
  156. policy_to_create = {
  157. "name": "TestPolicyClient",
  158. "description": "Test resource policy description",
  159. "scopes": ["test:read"],
  160. "clients": [client["clientId"]],
  161. }
  162. policy = uma.policy_resource_create(resource_id=resource_id, payload=policy_to_create)
  163. assert policy
  164. policy_to_create = {
  165. "name": "TestPolicyGroup",
  166. "description": "Test resource policy description",
  167. "scopes": ["test:read"],
  168. "groups": ["/UMAPolicyGroup"],
  169. }
  170. policy = uma.policy_resource_create(resource_id=resource_id, payload=policy_to_create)
  171. assert policy
  172. policies = uma.policy_query()
  173. assert len(policies) == 3
  174. policies = uma.policy_query(name="TestPolicyGroup")
  175. assert len(policies) == 1
  176. policy_id = policy["id"]
  177. uma.policy_delete(policy_id)
  178. with pytest.raises(KeycloakDeleteError) as err:
  179. uma.policy_delete(policy_id)
  180. assert err.match(
  181. '404: b\'{"error":"invalid_request","error_description":'
  182. '"Policy with .* does not exist"}\'',
  183. )
  184. policies = uma.policy_query()
  185. assert len(policies) == 2
  186. policy = policies[0]
  187. uma.policy_update(policy_id=policy["id"], payload=policy)
  188. policies = uma.policy_query()
  189. assert len(policies) == 2
  190. policies = uma.policy_query(name="Invalid")
  191. assert len(policies) == 0
  192. policies = uma.policy_query(scope="Invalid")
  193. assert len(policies) == 0
  194. policies = uma.policy_query(resource="Invalid")
  195. assert len(policies) == 0
  196. policies = uma.policy_query(first=3)
  197. assert len(policies) == 0
  198. policies = uma.policy_query(maximum=0)
  199. assert len(policies) == 0
  200. policies = uma.policy_query(name=policy["name"])
  201. assert len(policies) == 1
  202. policies = uma.policy_query(scope=policy["scopes"][0])
  203. assert len(policies) == 2
  204. policies = uma.policy_query(resource=resource_id)
  205. assert len(policies) == 2
  206. uma.resource_set_delete(resource_id)
  207. admin.delete_client(other_client_id)
  208. admin.delete_realm_role(role_id)
  209. admin.delete_group(group_id)
  210. def test_uma_access(uma: KeycloakUMA) -> None:
  211. """
  212. Test permission access checks.
  213. :param uma: Keycloak UMA client
  214. :type uma: KeycloakUMA
  215. """
  216. resource_to_create = {
  217. "name": "mytest",
  218. "scopes": ["read", "write"],
  219. "type": "urn:test",
  220. "ownerManagedAccess": True,
  221. }
  222. resource = uma.resource_set_create(resource_to_create)
  223. policy_to_create = {
  224. "name": "TestPolicy",
  225. "description": "Test resource policy description",
  226. "scopes": [resource_to_create["scopes"][0]],
  227. "clients": [uma.connection.client_id],
  228. }
  229. uma.policy_resource_create(resource_id=resource["_id"], payload=policy_to_create)
  230. token = uma.connection.token
  231. permissions = []
  232. assert uma.permissions_check(token["access_token"], permissions)
  233. permissions.append(UMAPermission(resource=resource_to_create["name"]))
  234. assert uma.permissions_check(token["access_token"], permissions)
  235. permissions.append(UMAPermission(resource="not valid"))
  236. assert not uma.permissions_check(token["access_token"], permissions)
  237. uma.resource_set_delete(resource["_id"])
  238. def test_uma_permission_ticket(uma: KeycloakUMA) -> None:
  239. """
  240. Test permission ticket generation.
  241. :param uma: Keycloak UMA client
  242. :type uma: KeycloakUMA
  243. """
  244. resource_to_create = {
  245. "name": "mytest",
  246. "scopes": ["read", "write"],
  247. "type": "urn:test",
  248. "ownerManagedAccess": True,
  249. }
  250. resource = uma.resource_set_create(resource_to_create)
  251. policy_to_create = {
  252. "name": "TestPolicy",
  253. "description": "Test resource policy description",
  254. "scopes": [resource_to_create["scopes"][0]],
  255. "clients": [uma.connection.client_id],
  256. }
  257. uma.policy_resource_create(resource_id=resource["_id"], payload=policy_to_create)
  258. permissions = (
  259. UMAPermission(resource=resource_to_create["name"], scope=resource_to_create["scopes"][0]),
  260. )
  261. response = uma.permission_ticket_create(permissions)
  262. rpt = uma.connection.keycloak_openid.token(
  263. grant_type="urn:ietf:params:oauth:grant-type:uma-ticket",
  264. ticket=response["ticket"],
  265. )
  266. assert rpt
  267. assert "access_token" in rpt
  268. permissions = (UMAPermission(resource="invalid"),)
  269. with pytest.raises(KeycloakPostError):
  270. uma.permission_ticket_create(permissions)
  271. uma.resource_set_delete(resource["_id"])
  272. # async function start
  273. @pytest.mark.asyncio
  274. async def test_a_uma_well_known(uma: KeycloakUMA) -> None:
  275. """
  276. Test the well_known method.
  277. :param uma: Keycloak UMA client
  278. :type uma: KeycloakUMA
  279. """
  280. res = uma.uma_well_known
  281. assert res is not None
  282. assert res != {}
  283. for key in ["resource_registration_endpoint"]:
  284. assert key in res
  285. @pytest.mark.asyncio
  286. async def test_a_uma_resource_sets(uma: KeycloakUMA) -> None:
  287. """
  288. Test resource sets.
  289. :param uma: Keycloak UMA client
  290. :type uma: KeycloakUMA
  291. """
  292. # Check that only the default resource is present
  293. resource_sets = uma.resource_set_list()
  294. resource_set_list = list(resource_sets)
  295. assert len(resource_set_list) == 1, resource_set_list
  296. assert resource_set_list[0]["name"] == "Default Resource", resource_set_list[0]["name"]
  297. # Test query for resource sets
  298. resource_set_list_ids = await uma.a_resource_set_list_ids()
  299. assert len(resource_set_list_ids) == 1
  300. resource_set_list_ids2 = await uma.a_resource_set_list_ids(name="Default")
  301. assert resource_set_list_ids2 == resource_set_list_ids
  302. resource_set_list_ids2 = await uma.a_resource_set_list_ids(name="Default Resource")
  303. assert resource_set_list_ids2 == resource_set_list_ids
  304. resource_set_list_ids = await uma.a_resource_set_list_ids(name="Default", exact_name=True)
  305. assert len(resource_set_list_ids) == 0
  306. resource_set_list_ids = await uma.a_resource_set_list_ids(first=1)
  307. assert len(resource_set_list_ids) == 0
  308. resource_set_list_ids = await uma.a_resource_set_list_ids(scope="Invalid")
  309. assert len(resource_set_list_ids) == 0
  310. resource_set_list_ids = await uma.a_resource_set_list_ids(owner="Invalid")
  311. assert len(resource_set_list_ids) == 0
  312. resource_set_list_ids = await uma.a_resource_set_list_ids(resource_type="Invalid")
  313. assert len(resource_set_list_ids) == 0
  314. resource_set_list_ids = await uma.a_resource_set_list_ids(name="Invalid")
  315. assert len(resource_set_list_ids) == 0
  316. resource_set_list_ids = await uma.a_resource_set_list_ids(uri="Invalid")
  317. assert len(resource_set_list_ids) == 0
  318. resource_set_list_ids = await uma.a_resource_set_list_ids(maximum=0)
  319. assert len(resource_set_list_ids) == 0
  320. # Test create resource set
  321. resource_to_create = {
  322. "name": "mytest",
  323. "scopes": ["test:read", "test:write"],
  324. "type": "urn:test",
  325. "uris": ["/some_resources/*"],
  326. }
  327. created_resource = await uma.a_resource_set_create(resource_to_create)
  328. assert created_resource
  329. assert created_resource["_id"], created_resource
  330. assert set(resource_to_create).issubset(set(created_resource)), created_resource
  331. # Test getting resource with wildcard
  332. # Without matchingUri query option
  333. resource_set_list_ids = await uma.a_resource_set_list_ids(uri="/some_resources/resource")
  334. assert len(resource_set_list_ids) == 0
  335. # With matchingUri query option
  336. resource_set_list_ids = await uma.a_resource_set_list_ids(
  337. uri="/some_resources/resource",
  338. matchingUri=True,
  339. )
  340. assert len(resource_set_list_ids) == 1
  341. # Test create the same resource set
  342. with pytest.raises(KeycloakPostError) as err:
  343. await uma.a_resource_set_create(resource_to_create)
  344. assert err.match(
  345. re.escape(
  346. '409: b\'{"error":"invalid_request","error_description":'
  347. '"Resource with name [mytest] already exists."}\'',
  348. ),
  349. )
  350. # Test get resource set
  351. latest_resource = await uma.a_resource_set_read(created_resource["_id"])
  352. assert latest_resource["name"] == created_resource["name"]
  353. # Test update resource set
  354. latest_resource["name"] = "New Resource Name"
  355. res = await uma.a_resource_set_update(created_resource["_id"], latest_resource)
  356. assert res == {}, res
  357. updated_resource = await uma.a_resource_set_read(created_resource["_id"])
  358. assert updated_resource["name"] == "New Resource Name"
  359. # Test update resource set fail
  360. with pytest.raises(KeycloakPutError) as err:
  361. uma.resource_set_update(resource_id=created_resource["_id"], payload={"wrong": "payload"})
  362. assert err.match("Unrecognized field")
  363. # Test delete resource set
  364. res = await uma.a_resource_set_delete(resource_id=created_resource["_id"])
  365. assert res == {}, res
  366. with pytest.raises(KeycloakGetError) as err:
  367. await uma.a_resource_set_read(created_resource["_id"])
  368. err.match("404: b''")
  369. # Test delete fail
  370. with pytest.raises(KeycloakDeleteError) as err:
  371. await uma.a_resource_set_delete(resource_id=created_resource["_id"])
  372. assert err.match("404: b''")
  373. @pytest.mark.asyncio
  374. async def test_a_uma_policy(uma: KeycloakUMA, admin: KeycloakAdmin) -> None:
  375. """
  376. Test policies.
  377. :param uma: Keycloak UMA client
  378. :type uma: KeycloakUMA
  379. :param admin: Keycloak Admin client
  380. :type admin: KeycloakAdmin
  381. """
  382. # Create some required test data
  383. resource_to_create = {
  384. "name": "mytest",
  385. "scopes": ["test:read", "test:write"],
  386. "type": "urn:test",
  387. "ownerManagedAccess": True,
  388. }
  389. created_resource = await uma.a_resource_set_create(resource_to_create)
  390. group_id = admin.create_group({"name": "UMAPolicyGroup"})
  391. role_id = admin.create_realm_role(payload={"name": "roleUMAPolicy"})
  392. other_client_id = admin.create_client({"name": "UMAOtherClient"})
  393. client = admin.get_client(other_client_id)
  394. resource_id = created_resource["_id"]
  395. # Create a role policy
  396. policy_to_create = {
  397. "name": "TestPolicyRole",
  398. "description": "Test resource policy description",
  399. "scopes": ["test:read", "test:write"],
  400. "roles": ["roleUMAPolicy"],
  401. }
  402. policy = await uma.a_policy_resource_create(resource_id=resource_id, payload=policy_to_create)
  403. assert policy
  404. # Create a client policy
  405. policy_to_create = {
  406. "name": "TestPolicyClient",
  407. "description": "Test resource policy description",
  408. "scopes": ["test:read"],
  409. "clients": [client["clientId"]],
  410. }
  411. policy = await uma.a_policy_resource_create(resource_id=resource_id, payload=policy_to_create)
  412. assert policy
  413. policy_to_create = {
  414. "name": "TestPolicyGroup",
  415. "description": "Test resource policy description",
  416. "scopes": ["test:read"],
  417. "groups": ["/UMAPolicyGroup"],
  418. }
  419. policy = await uma.a_policy_resource_create(resource_id=resource_id, payload=policy_to_create)
  420. assert policy
  421. policies = await uma.a_policy_query()
  422. assert len(policies) == 3
  423. policies = await uma.a_policy_query(name="TestPolicyGroup")
  424. assert len(policies) == 1
  425. policy_id = policy["id"]
  426. await uma.a_policy_delete(policy_id)
  427. with pytest.raises(KeycloakDeleteError) as err:
  428. await uma.a_policy_delete(policy_id)
  429. assert err.match(
  430. '404: b\'{"error":"invalid_request","error_description":'
  431. '"Policy with .* does not exist"}\'',
  432. )
  433. policies = await uma.a_policy_query()
  434. assert len(policies) == 2
  435. policy = policies[0]
  436. await uma.a_policy_update(policy_id=policy["id"], payload=policy)
  437. policies = await uma.a_policy_query()
  438. assert len(policies) == 2
  439. policies = await uma.a_policy_query(name="Invalid")
  440. assert len(policies) == 0
  441. policies = await uma.a_policy_query(scope="Invalid")
  442. assert len(policies) == 0
  443. policies = await uma.a_policy_query(resource="Invalid")
  444. assert len(policies) == 0
  445. policies = await uma.a_policy_query(first=3)
  446. assert len(policies) == 0
  447. policies = await uma.a_policy_query(maximum=0)
  448. assert len(policies) == 0
  449. policies = await uma.a_policy_query(name=policy["name"])
  450. assert len(policies) == 1
  451. policies = await uma.a_policy_query(scope=policy["scopes"][0])
  452. assert len(policies) == 2
  453. policies = await uma.a_policy_query(resource=resource_id)
  454. assert len(policies) == 2
  455. await uma.a_resource_set_delete(resource_id)
  456. await admin.a_delete_client(other_client_id)
  457. await admin.a_delete_realm_role(role_id)
  458. await admin.a_delete_group(group_id)
  459. @pytest.mark.asyncio
  460. async def test_a_uma_access(uma: KeycloakUMA) -> None:
  461. """
  462. Test permission access checks.
  463. :param uma: Keycloak UMA client
  464. :type uma: KeycloakUMA
  465. """
  466. resource_to_create = {
  467. "name": "mytest",
  468. "scopes": ["read", "write"],
  469. "type": "urn:test",
  470. "ownerManagedAccess": True,
  471. }
  472. resource = await uma.a_resource_set_create(resource_to_create)
  473. policy_to_create = {
  474. "name": "TestPolicy",
  475. "description": "Test resource policy description",
  476. "scopes": [resource_to_create["scopes"][0]],
  477. "clients": [uma.connection.client_id],
  478. }
  479. await uma.a_policy_resource_create(resource_id=resource["_id"], payload=policy_to_create)
  480. token = uma.connection.token
  481. permissions = []
  482. assert await uma.a_permissions_check(token["access_token"], permissions)
  483. permissions.append(UMAPermission(resource=resource_to_create["name"]))
  484. assert await uma.a_permissions_check(token["access_token"], permissions)
  485. permissions.append(UMAPermission(resource="not valid"))
  486. assert not await uma.a_permissions_check(token["access_token"], permissions)
  487. uma.resource_set_delete(resource["_id"])
  488. @pytest.mark.asyncio
  489. async def test_a_uma_permission_ticket(uma: KeycloakUMA) -> None:
  490. """
  491. Test permission ticket generation.
  492. :param uma: Keycloak UMA client
  493. :type uma: KeycloakUMA
  494. """
  495. resource_to_create = {
  496. "name": "mytest",
  497. "scopes": ["read", "write"],
  498. "type": "urn:test",
  499. "ownerManagedAccess": True,
  500. }
  501. resource = await uma.a_resource_set_create(resource_to_create)
  502. policy_to_create = {
  503. "name": "TestPolicy",
  504. "description": "Test resource policy description",
  505. "scopes": [resource_to_create["scopes"][0]],
  506. "clients": [uma.connection.client_id],
  507. }
  508. await uma.a_policy_resource_create(resource_id=resource["_id"], payload=policy_to_create)
  509. permissions = (
  510. UMAPermission(resource=resource_to_create["name"], scope=resource_to_create["scopes"][0]),
  511. )
  512. response = await uma.a_permission_ticket_create(permissions)
  513. rpt = await uma.connection.keycloak_openid.a_token(
  514. grant_type="urn:ietf:params:oauth:grant-type:uma-ticket",
  515. ticket=response["ticket"],
  516. )
  517. assert rpt
  518. assert "access_token" in rpt
  519. permissions = (UMAPermission(resource="invalid"),)
  520. with pytest.raises(KeycloakPostError):
  521. uma.permission_ticket_create(permissions)
  522. await uma.a_resource_set_delete(resource["_id"])
  523. def test_counter_part() -> None:
  524. """Test that each function has its async counter part."""
  525. uma_methods = [func for func in dir(KeycloakUMA) if callable(getattr(KeycloakUMA, func))]
  526. sync_methods = [
  527. method
  528. for method in uma_methods
  529. if not method.startswith("a_") and not method.startswith("_")
  530. ]
  531. async_methods = [
  532. method for method in uma_methods if iscoroutinefunction(getattr(KeycloakUMA, method))
  533. ]
  534. for method in sync_methods:
  535. async_method = f"a_{method}"
  536. assert (async_method in uma_methods) is True
  537. sync_sign = signature(getattr(KeycloakUMA, method))
  538. async_sign = signature(getattr(KeycloakUMA, async_method))
  539. assert sync_sign.parameters == async_sign.parameters
  540. for async_method in async_methods:
  541. if async_method[2:].startswith("_"):
  542. continue
  543. assert async_method[2:] in sync_methods