test_sms.py 8.0 KB

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