test_event_reports.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. # Copyright 2020 Dirk Klimpel
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import json
  15. import synapse.rest.admin
  16. from synapse.api.errors import Codes
  17. from synapse.rest.client.v1 import login, room
  18. from synapse.rest.client.v2_alpha import report_event
  19. from tests import unittest
  20. class EventReportsTestCase(unittest.HomeserverTestCase):
  21. servlets = [
  22. synapse.rest.admin.register_servlets,
  23. login.register_servlets,
  24. room.register_servlets,
  25. report_event.register_servlets,
  26. ]
  27. def prepare(self, reactor, clock, hs):
  28. self.admin_user = self.register_user("admin", "pass", admin=True)
  29. self.admin_user_tok = self.login("admin", "pass")
  30. self.other_user = self.register_user("user", "pass")
  31. self.other_user_tok = self.login("user", "pass")
  32. self.room_id1 = self.helper.create_room_as(
  33. self.other_user, tok=self.other_user_tok, is_public=True
  34. )
  35. self.helper.join(self.room_id1, user=self.admin_user, tok=self.admin_user_tok)
  36. self.room_id2 = self.helper.create_room_as(
  37. self.other_user, tok=self.other_user_tok, is_public=True
  38. )
  39. self.helper.join(self.room_id2, user=self.admin_user, tok=self.admin_user_tok)
  40. # Two rooms and two users. Every user sends and reports every room event
  41. for _ in range(5):
  42. self._create_event_and_report(
  43. room_id=self.room_id1,
  44. user_tok=self.other_user_tok,
  45. )
  46. for _ in range(5):
  47. self._create_event_and_report(
  48. room_id=self.room_id2,
  49. user_tok=self.other_user_tok,
  50. )
  51. for _ in range(5):
  52. self._create_event_and_report(
  53. room_id=self.room_id1,
  54. user_tok=self.admin_user_tok,
  55. )
  56. for _ in range(5):
  57. self._create_event_and_report(
  58. room_id=self.room_id2,
  59. user_tok=self.admin_user_tok,
  60. )
  61. self.url = "/_synapse/admin/v1/event_reports"
  62. def test_no_auth(self):
  63. """
  64. Try to get an event report without authentication.
  65. """
  66. channel = self.make_request("GET", self.url, b"{}")
  67. self.assertEqual(401, int(channel.result["code"]), msg=channel.result["body"])
  68. self.assertEqual(Codes.MISSING_TOKEN, channel.json_body["errcode"])
  69. def test_requester_is_no_admin(self):
  70. """
  71. If the user is not a server admin, an error 403 is returned.
  72. """
  73. channel = self.make_request(
  74. "GET",
  75. self.url,
  76. access_token=self.other_user_tok,
  77. )
  78. self.assertEqual(403, int(channel.result["code"]), msg=channel.result["body"])
  79. self.assertEqual(Codes.FORBIDDEN, channel.json_body["errcode"])
  80. def test_default_success(self):
  81. """
  82. Testing list of reported events
  83. """
  84. channel = self.make_request(
  85. "GET",
  86. self.url,
  87. access_token=self.admin_user_tok,
  88. )
  89. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  90. self.assertEqual(channel.json_body["total"], 20)
  91. self.assertEqual(len(channel.json_body["event_reports"]), 20)
  92. self.assertNotIn("next_token", channel.json_body)
  93. self._check_fields(channel.json_body["event_reports"])
  94. def test_limit(self):
  95. """
  96. Testing list of reported events with limit
  97. """
  98. channel = self.make_request(
  99. "GET",
  100. self.url + "?limit=5",
  101. access_token=self.admin_user_tok,
  102. )
  103. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  104. self.assertEqual(channel.json_body["total"], 20)
  105. self.assertEqual(len(channel.json_body["event_reports"]), 5)
  106. self.assertEqual(channel.json_body["next_token"], 5)
  107. self._check_fields(channel.json_body["event_reports"])
  108. def test_from(self):
  109. """
  110. Testing list of reported events with a defined starting point (from)
  111. """
  112. channel = self.make_request(
  113. "GET",
  114. self.url + "?from=5",
  115. access_token=self.admin_user_tok,
  116. )
  117. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  118. self.assertEqual(channel.json_body["total"], 20)
  119. self.assertEqual(len(channel.json_body["event_reports"]), 15)
  120. self.assertNotIn("next_token", channel.json_body)
  121. self._check_fields(channel.json_body["event_reports"])
  122. def test_limit_and_from(self):
  123. """
  124. Testing list of reported events with a defined starting point and limit
  125. """
  126. channel = self.make_request(
  127. "GET",
  128. self.url + "?from=5&limit=10",
  129. access_token=self.admin_user_tok,
  130. )
  131. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  132. self.assertEqual(channel.json_body["total"], 20)
  133. self.assertEqual(channel.json_body["next_token"], 15)
  134. self.assertEqual(len(channel.json_body["event_reports"]), 10)
  135. self._check_fields(channel.json_body["event_reports"])
  136. def test_filter_room(self):
  137. """
  138. Testing list of reported events with a filter of room
  139. """
  140. channel = self.make_request(
  141. "GET",
  142. self.url + "?room_id=%s" % self.room_id1,
  143. access_token=self.admin_user_tok,
  144. )
  145. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  146. self.assertEqual(channel.json_body["total"], 10)
  147. self.assertEqual(len(channel.json_body["event_reports"]), 10)
  148. self.assertNotIn("next_token", channel.json_body)
  149. self._check_fields(channel.json_body["event_reports"])
  150. for report in channel.json_body["event_reports"]:
  151. self.assertEqual(report["room_id"], self.room_id1)
  152. def test_filter_user(self):
  153. """
  154. Testing list of reported events with a filter of user
  155. """
  156. channel = self.make_request(
  157. "GET",
  158. self.url + "?user_id=%s" % self.other_user,
  159. access_token=self.admin_user_tok,
  160. )
  161. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  162. self.assertEqual(channel.json_body["total"], 10)
  163. self.assertEqual(len(channel.json_body["event_reports"]), 10)
  164. self.assertNotIn("next_token", channel.json_body)
  165. self._check_fields(channel.json_body["event_reports"])
  166. for report in channel.json_body["event_reports"]:
  167. self.assertEqual(report["user_id"], self.other_user)
  168. def test_filter_user_and_room(self):
  169. """
  170. Testing list of reported events with a filter of user and room
  171. """
  172. channel = self.make_request(
  173. "GET",
  174. self.url + "?user_id=%s&room_id=%s" % (self.other_user, self.room_id1),
  175. access_token=self.admin_user_tok,
  176. )
  177. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  178. self.assertEqual(channel.json_body["total"], 5)
  179. self.assertEqual(len(channel.json_body["event_reports"]), 5)
  180. self.assertNotIn("next_token", channel.json_body)
  181. self._check_fields(channel.json_body["event_reports"])
  182. for report in channel.json_body["event_reports"]:
  183. self.assertEqual(report["user_id"], self.other_user)
  184. self.assertEqual(report["room_id"], self.room_id1)
  185. def test_valid_search_order(self):
  186. """
  187. Testing search order. Order by timestamps.
  188. """
  189. # fetch the most recent first, largest timestamp
  190. channel = self.make_request(
  191. "GET",
  192. self.url + "?dir=b",
  193. access_token=self.admin_user_tok,
  194. )
  195. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  196. self.assertEqual(channel.json_body["total"], 20)
  197. self.assertEqual(len(channel.json_body["event_reports"]), 20)
  198. report = 1
  199. while report < len(channel.json_body["event_reports"]):
  200. self.assertGreaterEqual(
  201. channel.json_body["event_reports"][report - 1]["received_ts"],
  202. channel.json_body["event_reports"][report]["received_ts"],
  203. )
  204. report += 1
  205. # fetch the oldest first, smallest timestamp
  206. channel = self.make_request(
  207. "GET",
  208. self.url + "?dir=f",
  209. access_token=self.admin_user_tok,
  210. )
  211. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  212. self.assertEqual(channel.json_body["total"], 20)
  213. self.assertEqual(len(channel.json_body["event_reports"]), 20)
  214. report = 1
  215. while report < len(channel.json_body["event_reports"]):
  216. self.assertLessEqual(
  217. channel.json_body["event_reports"][report - 1]["received_ts"],
  218. channel.json_body["event_reports"][report]["received_ts"],
  219. )
  220. report += 1
  221. def test_invalid_search_order(self):
  222. """
  223. Testing that a invalid search order returns a 400
  224. """
  225. channel = self.make_request(
  226. "GET",
  227. self.url + "?dir=bar",
  228. access_token=self.admin_user_tok,
  229. )
  230. self.assertEqual(400, int(channel.result["code"]), msg=channel.result["body"])
  231. self.assertEqual(Codes.INVALID_PARAM, channel.json_body["errcode"])
  232. self.assertEqual("Unknown direction: bar", channel.json_body["error"])
  233. def test_limit_is_negative(self):
  234. """
  235. Testing that a negative limit parameter returns a 400
  236. """
  237. channel = self.make_request(
  238. "GET",
  239. self.url + "?limit=-5",
  240. access_token=self.admin_user_tok,
  241. )
  242. self.assertEqual(400, int(channel.result["code"]), msg=channel.result["body"])
  243. self.assertEqual(Codes.INVALID_PARAM, channel.json_body["errcode"])
  244. def test_from_is_negative(self):
  245. """
  246. Testing that a negative from parameter returns a 400
  247. """
  248. channel = self.make_request(
  249. "GET",
  250. self.url + "?from=-5",
  251. access_token=self.admin_user_tok,
  252. )
  253. self.assertEqual(400, int(channel.result["code"]), msg=channel.result["body"])
  254. self.assertEqual(Codes.INVALID_PARAM, channel.json_body["errcode"])
  255. def test_next_token(self):
  256. """
  257. Testing that `next_token` appears at the right place
  258. """
  259. # `next_token` does not appear
  260. # Number of results is the number of entries
  261. channel = self.make_request(
  262. "GET",
  263. self.url + "?limit=20",
  264. access_token=self.admin_user_tok,
  265. )
  266. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  267. self.assertEqual(channel.json_body["total"], 20)
  268. self.assertEqual(len(channel.json_body["event_reports"]), 20)
  269. self.assertNotIn("next_token", channel.json_body)
  270. # `next_token` does not appear
  271. # Number of max results is larger than the number of entries
  272. channel = self.make_request(
  273. "GET",
  274. self.url + "?limit=21",
  275. access_token=self.admin_user_tok,
  276. )
  277. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  278. self.assertEqual(channel.json_body["total"], 20)
  279. self.assertEqual(len(channel.json_body["event_reports"]), 20)
  280. self.assertNotIn("next_token", channel.json_body)
  281. # `next_token` does appear
  282. # Number of max results is smaller than the number of entries
  283. channel = self.make_request(
  284. "GET",
  285. self.url + "?limit=19",
  286. access_token=self.admin_user_tok,
  287. )
  288. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  289. self.assertEqual(channel.json_body["total"], 20)
  290. self.assertEqual(len(channel.json_body["event_reports"]), 19)
  291. self.assertEqual(channel.json_body["next_token"], 19)
  292. # Check
  293. # Set `from` to value of `next_token` for request remaining entries
  294. # `next_token` does not appear
  295. channel = self.make_request(
  296. "GET",
  297. self.url + "?from=19",
  298. access_token=self.admin_user_tok,
  299. )
  300. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  301. self.assertEqual(channel.json_body["total"], 20)
  302. self.assertEqual(len(channel.json_body["event_reports"]), 1)
  303. self.assertNotIn("next_token", channel.json_body)
  304. def _create_event_and_report(self, room_id, user_tok):
  305. """Create and report events"""
  306. resp = self.helper.send(room_id, tok=user_tok)
  307. event_id = resp["event_id"]
  308. channel = self.make_request(
  309. "POST",
  310. "rooms/%s/report/%s" % (room_id, event_id),
  311. json.dumps({"score": -100, "reason": "this makes me sad"}),
  312. access_token=user_tok,
  313. )
  314. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  315. def _check_fields(self, content):
  316. """Checks that all attributes are present in an event report"""
  317. for c in content:
  318. self.assertIn("id", c)
  319. self.assertIn("received_ts", c)
  320. self.assertIn("room_id", c)
  321. self.assertIn("event_id", c)
  322. self.assertIn("user_id", c)
  323. self.assertIn("sender", c)
  324. self.assertIn("canonical_alias", c)
  325. self.assertIn("name", c)
  326. self.assertIn("score", c)
  327. self.assertIn("reason", c)
  328. class EventReportDetailTestCase(unittest.HomeserverTestCase):
  329. servlets = [
  330. synapse.rest.admin.register_servlets,
  331. login.register_servlets,
  332. room.register_servlets,
  333. report_event.register_servlets,
  334. ]
  335. def prepare(self, reactor, clock, hs):
  336. self.admin_user = self.register_user("admin", "pass", admin=True)
  337. self.admin_user_tok = self.login("admin", "pass")
  338. self.other_user = self.register_user("user", "pass")
  339. self.other_user_tok = self.login("user", "pass")
  340. self.room_id1 = self.helper.create_room_as(
  341. self.other_user, tok=self.other_user_tok, is_public=True
  342. )
  343. self.helper.join(self.room_id1, user=self.admin_user, tok=self.admin_user_tok)
  344. self._create_event_and_report(
  345. room_id=self.room_id1,
  346. user_tok=self.other_user_tok,
  347. )
  348. # first created event report gets `id`=2
  349. self.url = "/_synapse/admin/v1/event_reports/2"
  350. def test_no_auth(self):
  351. """
  352. Try to get event report without authentication.
  353. """
  354. channel = self.make_request("GET", self.url, b"{}")
  355. self.assertEqual(401, int(channel.result["code"]), msg=channel.result["body"])
  356. self.assertEqual(Codes.MISSING_TOKEN, channel.json_body["errcode"])
  357. def test_requester_is_no_admin(self):
  358. """
  359. If the user is not a server admin, an error 403 is returned.
  360. """
  361. channel = self.make_request(
  362. "GET",
  363. self.url,
  364. access_token=self.other_user_tok,
  365. )
  366. self.assertEqual(403, int(channel.result["code"]), msg=channel.result["body"])
  367. self.assertEqual(Codes.FORBIDDEN, channel.json_body["errcode"])
  368. def test_default_success(self):
  369. """
  370. Testing get a reported event
  371. """
  372. channel = self.make_request(
  373. "GET",
  374. self.url,
  375. access_token=self.admin_user_tok,
  376. )
  377. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  378. self._check_fields(channel.json_body)
  379. def test_invalid_report_id(self):
  380. """
  381. Testing that an invalid `report_id` returns a 400.
  382. """
  383. # `report_id` is negative
  384. channel = self.make_request(
  385. "GET",
  386. "/_synapse/admin/v1/event_reports/-123",
  387. access_token=self.admin_user_tok,
  388. )
  389. self.assertEqual(400, int(channel.result["code"]), msg=channel.result["body"])
  390. self.assertEqual(Codes.INVALID_PARAM, channel.json_body["errcode"])
  391. self.assertEqual(
  392. "The report_id parameter must be a string representing a positive integer.",
  393. channel.json_body["error"],
  394. )
  395. # `report_id` is a non-numerical string
  396. channel = self.make_request(
  397. "GET",
  398. "/_synapse/admin/v1/event_reports/abcdef",
  399. access_token=self.admin_user_tok,
  400. )
  401. self.assertEqual(400, int(channel.result["code"]), msg=channel.result["body"])
  402. self.assertEqual(Codes.INVALID_PARAM, channel.json_body["errcode"])
  403. self.assertEqual(
  404. "The report_id parameter must be a string representing a positive integer.",
  405. channel.json_body["error"],
  406. )
  407. # `report_id` is undefined
  408. channel = self.make_request(
  409. "GET",
  410. "/_synapse/admin/v1/event_reports/",
  411. access_token=self.admin_user_tok,
  412. )
  413. self.assertEqual(400, int(channel.result["code"]), msg=channel.result["body"])
  414. self.assertEqual(Codes.INVALID_PARAM, channel.json_body["errcode"])
  415. self.assertEqual(
  416. "The report_id parameter must be a string representing a positive integer.",
  417. channel.json_body["error"],
  418. )
  419. def test_report_id_not_found(self):
  420. """
  421. Testing that a not existing `report_id` returns a 404.
  422. """
  423. channel = self.make_request(
  424. "GET",
  425. "/_synapse/admin/v1/event_reports/123",
  426. access_token=self.admin_user_tok,
  427. )
  428. self.assertEqual(404, int(channel.result["code"]), msg=channel.result["body"])
  429. self.assertEqual(Codes.NOT_FOUND, channel.json_body["errcode"])
  430. self.assertEqual("Event report not found", channel.json_body["error"])
  431. def _create_event_and_report(self, room_id, user_tok):
  432. """Create and report events"""
  433. resp = self.helper.send(room_id, tok=user_tok)
  434. event_id = resp["event_id"]
  435. channel = self.make_request(
  436. "POST",
  437. "rooms/%s/report/%s" % (room_id, event_id),
  438. json.dumps({"score": -100, "reason": "this makes me sad"}),
  439. access_token=user_tok,
  440. )
  441. self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
  442. def _check_fields(self, content):
  443. """Checks that all attributes are present in a event report"""
  444. self.assertIn("id", content)
  445. self.assertIn("received_ts", content)
  446. self.assertIn("room_id", content)
  447. self.assertIn("event_id", content)
  448. self.assertIn("user_id", content)
  449. self.assertIn("sender", content)
  450. self.assertIn("canonical_alias", content)
  451. self.assertIn("name", content)
  452. self.assertIn("event_json", content)
  453. self.assertIn("score", content)
  454. self.assertIn("reason", content)
  455. self.assertIn("auth_events", content["event_json"])
  456. self.assertIn("type", content["event_json"])
  457. self.assertIn("room_id", content["event_json"])
  458. self.assertIn("sender", content["event_json"])
  459. self.assertIn("content", content["event_json"])