test_volunteer.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. import uuid
  2. from httpx import AsyncClient
  3. from sqlalchemy import false, select
  4. from sqlalchemy.orm import Session
  5. from app.main import app
  6. from app.models import Project, Slot, Sms, User, Volunteer
  7. from app.tests.conftest import (
  8. default_project_id,
  9. default_volunteer_id,
  10. default_slot_id,
  11. )
  12. async def test_read_list_project_volunteers(
  13. client: AsyncClient, default_user_headers: dict, default_public_project: Project
  14. ):
  15. response = await client.get(
  16. app.url_path_for("list_project_volunteers", project_id=default_project_id),
  17. )
  18. assert response.status_code == 401
  19. response = await client.get(
  20. app.url_path_for("list_project_volunteers", project_id=uuid.uuid4()),
  21. headers=default_user_headers,
  22. )
  23. assert response.status_code == 404
  24. response = await client.get(
  25. app.url_path_for("list_project_volunteers", project_id="pas un uuid valid"),
  26. headers=default_user_headers,
  27. )
  28. assert response.status_code == 422
  29. response = await client.get(
  30. app.url_path_for("list_project_volunteers", project_id=default_project_id),
  31. headers=default_user_headers,
  32. )
  33. assert response.status_code == 200
  34. data = response.json()
  35. assert len(data) == 1
  36. volunteer_response = data[0]
  37. assert volunteer_response["name"] == "Arthur"
  38. assert volunteer_response["id"] == default_volunteer_id
  39. assert "created_at" in volunteer_response
  40. async def test_create_volunteer(
  41. client: AsyncClient,
  42. default_public_project: Project,
  43. default_user_headers: dict,
  44. session: Session,
  45. ):
  46. # Test without autentication
  47. response = await client.post(
  48. app.url_path_for("create_volunteer", project_id=default_project_id)
  49. )
  50. assert response.status_code == 401
  51. payload = {
  52. "name": "Lancelot",
  53. "email": "lancelot@dulac.fr",
  54. "phone_number": "03 14 15 92 65",
  55. }
  56. # test invalid project_id
  57. response = await client.post(
  58. app.url_path_for("create_volunteer", project_id=uuid.uuid4()),
  59. json=payload,
  60. headers=default_user_headers,
  61. )
  62. assert response.status_code == 404
  63. # Test normal payload
  64. response = await client.post(
  65. app.url_path_for("create_volunteer", project_id=default_project_id),
  66. json=payload,
  67. headers=default_user_headers,
  68. )
  69. assert response.status_code == 200
  70. assert response.json()["id"] != default_project_id
  71. assert response.json()["name"] == "Lancelot"
  72. assert response.json()["comment"] == ""
  73. result = session.execute(select(Volunteer).where(Volunteer.project_id == default_project_id))
  74. volunteers = result.scalars().all()
  75. assert len(volunteers) > 1
  76. # test invalid payload
  77. del payload["name"]
  78. response = await client.post(
  79. app.url_path_for("create_volunteer", project_id=default_project_id),
  80. json=payload,
  81. headers=default_user_headers,
  82. )
  83. assert response.status_code == 422
  84. async def test_create_volunteer_comment(
  85. client: AsyncClient,
  86. default_public_project: Project,
  87. default_user_headers: dict,
  88. session: Session,
  89. ):
  90. payload = {
  91. "name": "Lancelot",
  92. "email": "lancelot@dulac.fr",
  93. "phone_number": "03 14 15 92 65",
  94. "comment": "it's a knight",
  95. }
  96. # Test normal payload
  97. response = await client.post(
  98. app.url_path_for("create_volunteer", project_id=default_project_id),
  99. json=payload,
  100. headers=default_user_headers,
  101. )
  102. assert response.status_code == 200
  103. assert response.json()["id"] != default_project_id
  104. assert response.json()["name"] == "Lancelot"
  105. assert response.json()["comment"] != ""
  106. new_id = response.json()["id"]
  107. result = session.execute(select(Volunteer).where(Volunteer.id == new_id))
  108. volunteer = result.scalar_one_or_none()
  109. assert volunteer is not None
  110. assert volunteer.comment == "it's a knight"
  111. async def test_update_volunteer(
  112. client: AsyncClient,
  113. default_public_project: Project,
  114. default_user_headers: dict,
  115. session: Session,
  116. ):
  117. # Test without autentication
  118. response = await client.post(
  119. app.url_path_for(
  120. "update_volunteer",
  121. project_id=default_project_id,
  122. volunteer_id=default_volunteer_id,
  123. )
  124. )
  125. assert response.status_code == 401
  126. payload = {
  127. "name": "Lancelot",
  128. "email": "lancelot@dulac.fr",
  129. "phone_number": "03 14 15 92 65",
  130. "automatic_sms": False,
  131. "comment": "new comment",
  132. }
  133. # test invalid project_id
  134. response = await client.post(
  135. app.url_path_for(
  136. "update_volunteer",
  137. project_id=uuid.uuid4(),
  138. volunteer_id=default_volunteer_id,
  139. ),
  140. json=payload,
  141. headers=default_user_headers,
  142. )
  143. assert response.status_code == 404
  144. # test invalid volunteer_id
  145. response = await client.post(
  146. app.url_path_for(
  147. "update_volunteer",
  148. project_id=default_project_id,
  149. volunteer_id=uuid.uuid4(),
  150. ),
  151. json=payload,
  152. headers=default_user_headers,
  153. )
  154. assert response.status_code == 404
  155. # Test normal payload
  156. for k, v in payload.items():
  157. response = await client.post(
  158. app.url_path_for(
  159. "update_volunteer",
  160. project_id=default_project_id,
  161. volunteer_id=default_volunteer_id,
  162. ),
  163. json={k: v},
  164. headers=default_user_headers,
  165. )
  166. assert response.status_code == 200
  167. assert response.json()["id"] == default_volunteer_id
  168. assert response.json()[k] == v
  169. async def test_update_volunteer_slots(
  170. client: AsyncClient,
  171. default_public_project: Project,
  172. default_user_headers: dict,
  173. session: Session,
  174. ):
  175. response = await client.post(
  176. app.url_path_for(
  177. "update_volunteer",
  178. project_id=default_project_id,
  179. volunteer_id=default_volunteer_id,
  180. ),
  181. json={"slots": []},
  182. headers=default_user_headers,
  183. )
  184. assert response.status_code == 200
  185. result = session.execute(select(Slot).where(Slot.id == default_slot_id))
  186. slot = result.scalars().first()
  187. assert slot is not None
  188. assert slot.volunteers_id == []
  189. response = await client.post(
  190. app.url_path_for(
  191. "update_volunteer",
  192. project_id=default_project_id,
  193. volunteer_id=default_volunteer_id,
  194. ),
  195. json={"slots": [default_slot_id]},
  196. headers=default_user_headers,
  197. )
  198. assert response.status_code == 200
  199. session.refresh(slot)
  200. assert slot is not None
  201. assert slot.volunteers_id == [default_volunteer_id]
  202. # An invalid slot list
  203. response = await client.post(
  204. app.url_path_for(
  205. "update_volunteer",
  206. project_id=default_project_id,
  207. volunteer_id=default_volunteer_id,
  208. ),
  209. json={"slots": [str(uuid.uuid4())]},
  210. headers=default_user_headers,
  211. )
  212. assert response.status_code == 400
  213. # An invalid slot list
  214. response = await client.post(
  215. app.url_path_for(
  216. "update_volunteer",
  217. project_id=default_project_id,
  218. volunteer_id=default_volunteer_id,
  219. ),
  220. json={"slots": ["not uuid str"]},
  221. headers=default_user_headers,
  222. )
  223. assert response.status_code == 422
  224. async def test_delete_volunteer(
  225. client: AsyncClient,
  226. default_user_headers: dict,
  227. session: Session,
  228. default_public_project: Project,
  229. ):
  230. # Fail deleting the project due to not logged in
  231. response = await client.delete(
  232. app.url_path_for(
  233. "delete_volunteer",
  234. project_id=default_project_id,
  235. volunteer_id=default_volunteer_id,
  236. )
  237. )
  238. assert response.status_code == 401
  239. result = session.execute(select(Volunteer).where(Volunteer.id == default_volunteer_id))
  240. volunteer = result.scalars().first()
  241. assert volunteer is not None
  242. # Proper deletion
  243. response = await client.delete(
  244. app.url_path_for(
  245. "delete_volunteer",
  246. project_id=default_project_id,
  247. volunteer_id=default_volunteer_id,
  248. ),
  249. headers=default_user_headers,
  250. )
  251. assert response.status_code == 200
  252. result = session.execute(select(Volunteer).where(Volunteer.id == default_volunteer_id))
  253. volunteer = result.scalars().first()
  254. assert volunteer is None
  255. # check deletion is cascaded to slots
  256. result = session.execute(select(Slot).where(Slot.id == default_slot_id))
  257. slot: Slot | None = result.scalar_one_or_none()
  258. assert slot is not None
  259. assert default_volunteer_id not in slot.volunteers_id
  260. # Idempotence test
  261. response = await client.delete(
  262. app.url_path_for(
  263. "delete_volunteer",
  264. project_id=default_project_id,
  265. volunteer_id=default_volunteer_id,
  266. ),
  267. headers=default_user_headers,
  268. )
  269. assert response.status_code == 200
  270. async def test_delete_volunteer_any_uuid(
  271. client: AsyncClient,
  272. default_user_headers: dict,
  273. session: Session,
  274. default_public_project: Project,
  275. ):
  276. # can delete random uuid
  277. response = await client.delete(
  278. app.url_path_for(
  279. "delete_volunteer", project_id=default_project_id, volunteer_id=uuid.uuid4()
  280. ),
  281. headers=default_user_headers,
  282. )
  283. assert response.status_code == 200
  284. # Cannot delete non uuid string
  285. response = await client.delete(
  286. app.url_path_for(
  287. "delete_volunteer", project_id=default_project_id, volunteer_id="not uidstr"
  288. ),
  289. headers=default_user_headers,
  290. )
  291. assert response.status_code == 422
  292. async def test_delete_volunteer_with_sms(
  293. client: AsyncClient,
  294. default_user_headers: dict,
  295. session: Session,
  296. default_public_project: Project,
  297. ):
  298. sms = Sms()
  299. sms.project_id = default_project_id
  300. sms.content = "coucou"
  301. sms.phone_number = "02 66 66 66 66 66"
  302. sms.volunteer_id = default_volunteer_id
  303. session.add(sms)
  304. session.commit()
  305. session.refresh(sms)
  306. response = await client.delete(
  307. app.url_path_for(
  308. "delete_volunteer",
  309. project_id=default_project_id,
  310. volunteer_id=default_volunteer_id,
  311. ),
  312. headers=default_user_headers,
  313. )
  314. assert response.status_code == 200
  315. # Volunteer must be deleted
  316. result = session.execute(select(Volunteer).where(Volunteer.id == default_volunteer_id))
  317. assert result.scalar_one_or_none() is None
  318. # Sms must be deleted
  319. assert session.execute(select(Sms).where(Sms.id == sms.id)).scalar_one_or_none() is None