test_sms.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. from datetime import datetime, timezone
  2. import uuid
  3. from httpx import AsyncClient
  4. from sqlalchemy import select
  5. from sqlalchemy.orm import Session
  6. from app.main import app
  7. from app.models import Project, Sms, Volunteer
  8. from app.tests.conftest import default_project_id, default_volunteer_id, default_sms_id
  9. async def test_read_list_project_sms(
  10. client: AsyncClient, default_user_headers: dict, default_public_project: Project
  11. ):
  12. response = await client.get(
  13. app.url_path_for("list_project_sms", project_id=default_project_id),
  14. )
  15. assert response.status_code == 401
  16. response = await client.get(
  17. app.url_path_for("list_project_sms", project_id=uuid.uuid4()),
  18. headers=default_user_headers,
  19. )
  20. assert response.status_code == 404
  21. response = await client.get(
  22. app.url_path_for("list_project_sms", project_id="pas un uuid valid"),
  23. headers=default_user_headers,
  24. )
  25. assert response.status_code == 422
  26. response = await client.get(
  27. app.url_path_for("list_project_sms", project_id=default_project_id),
  28. headers=default_user_headers,
  29. )
  30. assert response.status_code == 200
  31. data = response.json()
  32. assert len(data) == 1
  33. assert data[0]["id"] == default_sms_id
  34. async def test_create_sms(
  35. client: AsyncClient,
  36. default_public_project: Project,
  37. default_user_headers: dict,
  38. session: Session,
  39. ):
  40. # Test without autentication
  41. response = await client.post(
  42. app.url_path_for("create_sms", project_id=default_project_id)
  43. )
  44. assert response.status_code == 401
  45. payload = {"phone_number": "06 75 75 75 75 ", "content": "sms_content"}
  46. # test invalid project_id
  47. response = await client.post(
  48. app.url_path_for("create_sms", project_id=uuid.uuid4()),
  49. json=payload,
  50. headers=default_user_headers,
  51. )
  52. assert response.status_code == 404
  53. # Test normal payload
  54. before_creation_time = datetime.now(timezone.utc)
  55. response = await client.post(
  56. app.url_path_for("create_sms", project_id=default_project_id),
  57. json=payload,
  58. headers=default_user_headers,
  59. )
  60. assert response.status_code == 200
  61. assert response.json()["content"] == "sms_content"
  62. result = session.execute(
  63. select(Sms).where(
  64. (Sms.project_id == default_project_id) & (Sms.id != default_sms_id)
  65. )
  66. )
  67. sms = result.scalars().first()
  68. assert sms is not None
  69. assert sms.content == "sms_content"
  70. assert before_creation_time < sms.sending_time
  71. assert sms.sending_time < datetime.now(timezone.utc)
  72. # test invalid payload
  73. del payload["content"]
  74. response = await client.post(
  75. app.url_path_for("create_sms", project_id=default_project_id),
  76. json=payload,
  77. headers=default_user_headers,
  78. )
  79. assert response.status_code == 422
  80. async def test_update_sms(
  81. client: AsyncClient,
  82. default_public_project: Project,
  83. default_user_headers: dict,
  84. session: Session,
  85. ):
  86. # Test without autentication
  87. response = await client.post(
  88. app.url_path_for(
  89. "update_sms",
  90. project_id=default_project_id,
  91. sms_id=default_sms_id,
  92. )
  93. )
  94. assert response.status_code == 401
  95. # Test invalid payload
  96. response = await client.post(
  97. app.url_path_for(
  98. "update_sms",
  99. project_id=default_project_id,
  100. sms_id=default_sms_id,
  101. ),
  102. json={"volunteer_id": True},
  103. headers=default_user_headers,
  104. )
  105. assert response.status_code == 422
  106. payload = {
  107. "volunteer_id": default_volunteer_id,
  108. "phone_number": "06 75 75 75 75 ",
  109. "content": "sms_content",
  110. "sending_time": datetime(2024, 5, 17, tzinfo=timezone.utc).isoformat(),
  111. }
  112. # test invalid project_id
  113. response = await client.post(
  114. app.url_path_for(
  115. "update_sms",
  116. project_id=uuid.uuid4(),
  117. sms_id=default_sms_id,
  118. ),
  119. json=payload,
  120. headers=default_user_headers,
  121. )
  122. assert response.status_code == 404
  123. # test invalid sms_id
  124. response = await client.post(
  125. app.url_path_for(
  126. "update_sms",
  127. project_id=default_project_id,
  128. sms_id=uuid.uuid4(),
  129. ),
  130. json=payload,
  131. headers=default_user_headers,
  132. )
  133. assert response.status_code == 404
  134. # Test normal payload
  135. for k, v in payload.items():
  136. response = await client.post(
  137. app.url_path_for(
  138. "update_sms",
  139. project_id=default_project_id,
  140. sms_id=default_sms_id,
  141. ),
  142. json={k: v},
  143. headers=default_user_headers,
  144. )
  145. assert response.status_code == 200
  146. assert response.json()["id"] == default_sms_id
  147. if "time" in k:
  148. parsed_time = datetime.fromisoformat(response.json()[k])
  149. assert parsed_time == datetime.fromisoformat(v)
  150. else:
  151. assert response.json()[k] == v
  152. async def test_delete_sms(
  153. client: AsyncClient,
  154. default_user_headers: dict,
  155. session: Session,
  156. default_public_project: Project,
  157. ):
  158. # Fail deleting the project due to not logged in
  159. response = await client.delete(
  160. app.url_path_for(
  161. "delete_sms",
  162. project_id=default_project_id,
  163. sms_id=default_sms_id,
  164. )
  165. )
  166. assert response.status_code == 401
  167. result = session.execute(select(Sms).where(Sms.id == default_sms_id))
  168. sms = result.scalars().first()
  169. assert sms is not None
  170. # Proper deletion
  171. response = await client.delete(
  172. app.url_path_for(
  173. "delete_sms",
  174. project_id=default_project_id,
  175. sms_id=default_sms_id,
  176. ),
  177. headers=default_user_headers,
  178. )
  179. assert response.status_code == 200
  180. result = session.execute(select(Sms).where(Sms.id == default_sms_id))
  181. sms = result.scalars().first()
  182. assert sms is None
  183. # Idempotence test
  184. response = await client.delete(
  185. app.url_path_for(
  186. "delete_sms",
  187. project_id=default_project_id,
  188. sms_id=default_sms_id,
  189. ),
  190. headers=default_user_headers,
  191. )
  192. assert response.status_code == 200
  193. # can delete random uuid
  194. response = await client.delete(
  195. app.url_path_for(
  196. "delete_sms", project_id=default_project_id, sms_id=uuid.uuid4()
  197. ),
  198. headers=default_user_headers,
  199. )
  200. assert response.status_code == 200
  201. # Cannot delete non uuid string
  202. response = await client.delete(
  203. app.url_path_for(
  204. "delete_sms", project_id=default_project_id, sms_id="not uidstr"
  205. ),
  206. headers=default_user_headers,
  207. )
  208. assert response.status_code == 422
  209. async def test_delete_sms_with_volunteer(
  210. client: AsyncClient,
  211. default_user_headers: dict,
  212. session: Session,
  213. default_public_project: Project,
  214. ):
  215. result = session.execute(
  216. select(Volunteer).where(Volunteer.id == default_volunteer_id)
  217. )
  218. volunteer = result.scalars().first()
  219. assert volunteer is not None
  220. assert len(volunteer.sms) == 0
  221. result = session.execute(select(Sms).where(Sms.id == default_sms_id))
  222. sms = result.scalars().first()
  223. assert sms is not None
  224. sms.volunteer_id = default_volunteer_id
  225. session.commit()
  226. session.refresh(volunteer)
  227. assert len(volunteer.sms) == 1, "Sms not added to volunteer"
  228. response = await client.delete(
  229. app.url_path_for(
  230. "delete_sms",
  231. project_id=default_project_id,
  232. sms_id=default_sms_id,
  233. ),
  234. headers=default_user_headers,
  235. )
  236. assert response.status_code == 200
  237. result = session.execute(select(Sms).where(Sms.id == default_sms_id))
  238. assert result.scalars().first() is None
  239. session.refresh(volunteer)
  240. assert len(volunteer.sms) == 0, "Sms should be deleted"
  241. result = session.execute(
  242. select(Volunteer).where(Volunteer.id == default_volunteer_id)
  243. )
  244. volunteer_result = result.scalars().first()
  245. assert volunteer_result is not None, "Volunteer should not be deleted"
  246. assert len(volunteer_result.sms) == 0, "No more sms associated to volunteer"