wip: currently rewriting the project as a full stack application
tangled.org/kacaii.dev/sigo
gleam
1import app/domain/occurrence/category
2import app/domain/occurrence/priority
3import app/domain/occurrence/sql as o_sql
4import app/domain/occurrence/subcategory
5import app/http_router
6import app/web
7import app_dev/sql as dev_sql
8import app_test
9import dummy
10import gleam/dynamic/decode
11import gleam/float
12import gleam/http
13import gleam/json
14import gleam/list
15import gleam/option
16import gleam/set
17import wisp
18import wisp/simulate
19import youid/uuid
20
21pub fn register_new_occurrence_test() {
22 use ctx <- app_test.global_data()
23 use _ <- list.each(list.range(1, app_test.n_tests))
24
25 // DUMMY USERS -----------------------------------------------------------
26 let dummy_applicant_id = dummy.random_user(ctx.db)
27 let dummy_participants_id = {
28 list.map(list.range(0, 12), fn(_) { dummy.random_user(ctx.db) })
29 }
30
31 // DUMMY BRIGADE -------------------------------------------------------------
32 let dummy_brigade_id =
33 dummy.random_brigade(
34 conn: ctx.db,
35 leader_id: dummy_applicant_id,
36 members: dummy_participants_id,
37 )
38
39 // REQUEST -------------------------------------------------------------------
40 let oc_category = category.to_string(dummy.random_category())
41 let oc_subcategory = subcategory.to_string(dummy.random_subcategory())
42 let oc_priority = priority.to_string(dummy.random_priority())
43 let coords = [float.random() *. 100.0, float.random() *. 100.0]
44 let oc_assigned_brigades =
45 json.array([uuid.to_string(dummy_brigade_id)], json.string)
46
47 let req =
48 simulate.browser_request(http.Post, "/occurrence/new")
49 |> simulate.json_body(
50 json.object([
51 #("categoria", json.string(oc_category)),
52 #("subcategoria", json.string(oc_subcategory)),
53 #("prioridade", json.string(oc_priority)),
54 #("descricao", json.string(wisp.random_string(33))),
55 #("gps", json.array(coords, json.float)),
56 #("pontoDeReferencia", json.string(wisp.random_string(33))),
57 #("idEquipes", oc_assigned_brigades),
58 ]),
59 )
60
61 // RESPONSE ------------------------------------------------------------------
62 let resp = http_router.handle_request(req, ctx)
63 assert resp.status != 422 as "Invalid request Payload"
64 assert resp.status == 401 as "Endpoint restricted to authenticated users"
65
66 let with_auth = app_test.with_authorization(next: req)
67 let resp = http_router.handle_request(with_auth, ctx)
68 assert resp.status == 201 as "HTTP 201 Created"
69
70 // JSON PARSING --------------------------------------------------------------
71 let body = simulate.read_body(resp)
72 let assert Ok(dummy_occurrence_id) =
73 json.parse(body, {
74 use _ <- decode.field("priority", priority.decoder_pt_br())
75
76 use dummy_occurrence_id <- decode.field(
77 "id",
78 web.uuid_decoder("occurrence_uuid"),
79 )
80
81 use _ <- decode.field(
82 "applicant_id",
83 decode.optional(web.uuid_decoder("applicant_uuid")),
84 )
85
86 use _ <- decode.field(
87 "assigned_brigades",
88 decode.list(web.uuid_decoder("brigade_uuid")),
89 )
90
91 use _ <- decode.field("created_at", decode.float)
92
93 decode.success(dummy_occurrence_id)
94 })
95 as "Response contain valid JSON"
96
97 // Check if users were registered as participants ----------------------------
98 let dummy_participants_set = set.from_list(dummy_participants_id)
99
100 let registered_participants_set =
101 set.from_list({
102 let assert Ok(returned) =
103 o_sql.query_participants(ctx.db, dummy_occurrence_id)
104 as "Query occurrence participants"
105
106 use row <- list.map(returned.rows)
107 row.user_id
108 })
109
110 assert set.difference(registered_participants_set, dummy_participants_set)
111 |> set.to_list()
112 == []
113 as "Registered members contain all expected users"
114
115 assert set.difference(dummy_participants_set, registered_participants_set)
116 |> set.to_list()
117 == []
118 as "Participants were assigned correclty"
119
120 // CLEANUP ----------------------------------------------------------------
121 let assert Ok(_) = dev_sql.truncate_occurrence(ctx.db)
122 let assert Ok(_) = dev_sql.truncate_brigade(ctx.db)
123 let assert Ok(_) = dev_sql.soft_truncate_user_account(ctx.db)
124}
125
126pub fn get_occurrences_by_applicant_test() {
127 use ctx <- app_test.global_data()
128 use _ <- list.each(list.range(1, app_test.n_tests))
129
130 // DUMMY USERS -----------------------------------------------------------
131 let dummy_applicant_id = dummy.random_user(ctx.db)
132 let dummy_participants_id = {
133 list.map(list.range(0, 12), fn(_) { dummy.random_user(ctx.db) })
134 }
135
136 // DUMMY BRIGADE -------------------------------------------------------------
137 let dummy_brigade_id =
138 dummy.random_brigade(
139 conn: ctx.db,
140 leader_id: dummy_applicant_id,
141 members: dummy_participants_id,
142 )
143
144 // DUMMY OCCURRENCE ----------------------------------------------------------
145 let dummy_occurrence =
146 dummy.random_occurrence(ctx.db, dummy_applicant_id, [dummy_brigade_id])
147
148 let path = "/user/" <> uuid.to_string(dummy_applicant_id) <> "/occurrences"
149 let req = simulate.browser_request(http.Get, path)
150
151 let resp = http_router.handle_request(req, ctx)
152 let body = simulate.read_body(resp)
153 assert resp.status == 200
154
155 // JSON PARSING --------------------------------------------------------------
156 let assert Ok(_) =
157 json.parse(body, {
158 let call_decoder = {
159 use _ <- decode.field("tipo", category.decoder_pt_br())
160 use _ <- decode.field("detalhes", decode.string)
161 use _ <- decode.field("solicitante", {
162 use name <- decode.field("nome", decode.string)
163 decode.success(name)
164 })
165 decode.success(Nil)
166 }
167
168 let occurrence_timestamp_decoder = {
169 use _ <- decode.field("abertura", decode.float)
170 use _ <- decode.field("chegadaNoLocal", decode.optional(decode.float))
171 use _ <- decode.field("finalizacao", decode.optional(decode.float))
172 decode.success(Nil)
173 }
174
175 let occurrence_metadata_decoder = {
176 use _ <- decode.field("usuarioId", web.uuid_decoder("user_uuid"))
177 use _ <- decode.field("matriculaUsuario", decode.string)
178 use _ <- decode.field("nomeUsuario", decode.string)
179 decode.success(Nil)
180 }
181
182 let occurrence_brigade_list_decoder =
183 decode.list({
184 use _ <- decode.field("id", web.uuid_decoder("brigade_uuid"))
185 use _ <- decode.field("nomeEquipe", decode.string)
186 use _ <- decode.field("codigoViatura", decode.string)
187 use _ <- decode.field("lider", decode.string)
188 decode.success(Nil)
189 })
190
191 decode.list({
192 use id <- decode.field("id", web.uuid_decoder("call_uuid?"))
193 use _ <- decode.field("status", decode.string)
194 use _ <- decode.field("prioridade", priority.decoder_pt_br())
195 use _ <- decode.field("chamado", call_decoder)
196 use _ <- decode.field(
197 "coordenadas",
198 decode.optional(decode.list(decode.float)),
199 )
200 use _ <- decode.field("timestamps", occurrence_timestamp_decoder)
201 use _ <- decode.field("metadata", occurrence_metadata_decoder)
202 use _ <- decode.field("equipes", occurrence_brigade_list_decoder)
203
204 assert id == dummy_occurrence
205 as "Occurence uuid should be the same as the dummy one"
206
207 decode.success(Nil)
208 })
209 })
210
211 // CLEANUP ----------------------------------------------------------------
212 let assert Ok(_) = dev_sql.truncate_occurrence(ctx.db)
213 let assert Ok(_) = dev_sql.truncate_brigade(ctx.db)
214 let assert Ok(_) = dev_sql.soft_truncate_user_account(ctx.db)
215}
216
217pub fn delete_occurrence_test() {
218 use ctx <- app_test.global_data()
219 use _ <- list.each(list.range(1, app_test.n_tests))
220
221 // DUMMY
222 let dummy_applicant = dummy.random_user(ctx.db)
223 let dummy_occurrence =
224 dummy.random_occurrence(ctx.db, applicant_id: dummy_applicant, assign: [])
225
226 let path = "/occurrence/" <> uuid.to_string(dummy_occurrence)
227 let req = simulate.request(http.Delete, path)
228 let resp = http_router.handle_request(req, ctx)
229
230 assert resp.status == 401 as "Only accessible to Admins"
231
232 let with_auth = app_test.with_authorization(req)
233 let resp = http_router.handle_request(with_auth, ctx)
234
235 assert resp.status == 200 as "Status should be HTTP 200 OK"
236
237 let body = simulate.read_body(resp)
238 let assert Ok(deleted_occurrence) =
239 json.parse(body, {
240 use id <- decode.field("id", web.uuid_decoder("occurrence_uuid"))
241 decode.success(id)
242 })
243
244 assert deleted_occurrence == dummy_occurrence
245 as "Deleted the wrong Occurrence"
246
247 // CLEANUP ----------------------------------------------------------------
248 let assert Ok(_) = dev_sql.soft_truncate_user_account(ctx.db)
249}
250
251pub fn close_occurrence_test() {
252 use ctx <- app_test.global_data()
253 let base_path = "/occurrence/close/"
254 use _ <- list.each(list.range(1, app_test.n_tests))
255
256 // DUMMY ---------------------------------------------------------------------
257 let dummy_applicant = dummy.random_user(ctx.db)
258 let dummy_members =
259 list.map(list.range(1, 10), fn(_) { dummy.random_user(ctx.db) })
260
261 let dummy_brigade =
262 dummy.random_brigade(ctx.db, dummy_applicant, dummy_members)
263
264 let dummy_occurrence =
265 dummy.random_occurrence(
266 conn: ctx.db,
267 applicant_id: dummy_applicant,
268 assign: [dummy_brigade],
269 )
270
271 let path = base_path <> uuid.to_string(dummy_occurrence)
272 let req = simulate.request(http.Post, path)
273 let resp = http_router.handle_request(req, ctx)
274
275 assert resp.status == 401 as "Restricted to authenticated Users"
276
277 // Response decoder
278 let resp_decoder = {
279 let resolved_at_decoder = decode.optional(decode.float)
280
281 use occ_id <- decode.field("id", web.uuid_decoder("occurrence_uuid"))
282 use resolved_at <- decode.field("resolved_at", resolved_at_decoder)
283 use _ <- decode.field("updated_at", decode.float)
284
285 assert option.is_some(resolved_at) as "Occurrence should be closed"
286 assert occ_id == dummy_occurrence as "Update the correct occurrence"
287 decode.success(Nil)
288 }
289
290 let _happy_path = {
291 let req = app_test.with_authorization(req)
292 let resp = http_router.handle_request(req, ctx)
293 let body = simulate.read_body(resp)
294
295 let assert Ok(_) = json.parse(body, resp_decoder)
296 as "Json response should be valid"
297 }
298
299 // CLEANUP ----------------------------------------------------------------
300 let assert Ok(_) = dev_sql.truncate_occurrence(ctx.db)
301 let assert Ok(_) = dev_sql.truncate_brigade(ctx.db)
302 let assert Ok(_) = dev_sql.soft_truncate_user_account(ctx.db)
303}
304
305pub fn close_missing_occurrence_test() {
306 use ctx <- app_test.global_data()
307 let base_path = "/occurrence/close/"
308 let path = base_path <> uuid.v7_string()
309
310 let req =
311 simulate.browser_request(http.Post, path)
312 |> app_test.with_authorization()
313
314 let resp = http_router.handle_request(req, ctx)
315 assert resp.status == 404 as "Cant resolve missing occurrence"
316}
317
318pub fn reopen_occurrence_test() {
319 use ctx <- app_test.global_data()
320 let base_path = "/occurrence/reopen/"
321 use _ <- list.each(list.range(1, app_test.n_tests))
322
323 // DUMMY ---------------------------------------------------------------------
324 let dummy_applicant = dummy.random_user(ctx.db)
325 let dummy_members =
326 list.map(list.range(1, 10), fn(_) { dummy.random_user(ctx.db) })
327
328 let dummy_brigade =
329 dummy.random_brigade(ctx.db, dummy_applicant, dummy_members)
330
331 let dummy_occurrence =
332 dummy.random_occurrence(
333 conn: ctx.db,
334 applicant_id: dummy_applicant,
335 assign: [dummy_brigade],
336 )
337
338 let path = base_path <> uuid.to_string(dummy_occurrence)
339 let req = simulate.request(http.Post, path)
340 let resp = http_router.handle_request(req, ctx)
341
342 assert resp.status == 401 as "Restricted to authenticated Users"
343 let req = app_test.with_authorization(req)
344 let resp = http_router.handle_request(req, ctx)
345 let body = simulate.read_body(resp)
346
347 let assert Ok(_) =
348 json.parse(body, {
349 let resolved_at_decoder = decode.optional(decode.float)
350
351 use occ_id <- decode.field("id", web.uuid_decoder("occurrence_uuid"))
352 use resolved_at <- decode.field("resolved_at", resolved_at_decoder)
353 use _ <- decode.field("updated_at", decode.float)
354
355 assert option.is_none(resolved_at) as "Occurrence should be open"
356 assert occ_id == dummy_occurrence as "Update the correct occurrence"
357 decode.success(Nil)
358 })
359
360 // CLEANUP ----------------------------------------------------------------
361 let assert Ok(_) = dev_sql.truncate_occurrence(ctx.db)
362 let assert Ok(_) = dev_sql.truncate_brigade(ctx.db)
363 let assert Ok(_) = dev_sql.soft_truncate_user_account(ctx.db)
364}
365
366pub fn reopen_missing_occurrence_test() {
367 use ctx <- app_test.global_data()
368 let base_path = "/occurrence/reopen/"
369 let path = base_path <> uuid.v7_string()
370
371 let req =
372 simulate.browser_request(http.Post, path)
373 |> app_test.with_authorization()
374
375 let resp = http_router.handle_request(req, ctx)
376 assert resp.status == 404 as "Cant reopen missing occurrence"
377}