import gleeunit import gleeunit/should import mist import gleam/bit_builder import gleam/http import gleam/http/request import gleam/http/response import gleam/erlang/atom.{Atom} import gleam/erlang/process import gleam/uri import gleam/string import gleam/list import finch import finch/otp const base_url = "http://localhost:33100" pub fn main() { assert Ok(_) = mist.run_service( 33_100, fn(req) { case req.method, request.path_segments(req) { http.Get, ["ok"] -> response.new(200) |> response.set_body(bit_builder.from_string("OK")) http.Post, ["post"] -> response.new(500) |> response.set_body(bit_builder.from_bit_string(req.body)) http.Delete, ["headers"] -> response.new(200) |> response.set_body(bit_builder.from_string(string.inspect( req.headers, ))) |> response.set_header("x-token", "token-x") } }, max_body_limit: 4_000_000, ) configure_logger([Level(None)]) gleeunit.main() } pub fn ok_req_test() { use <- with_finch() assert Ok(url) = uri.parse(ok_url()) assert Ok(req) = request.from_uri(url) let finch_req = finch.build(req, []) assert Ok(resp) = finch.request(finch_req, server_name()) should.equal(resp.status, 200) should.equal(resp.body, "OK") } pub fn post_data_test() { let body = "FOOBAR" use <- with_finch() assert Ok(url) = uri.parse(post_url()) assert Ok(req) = request.from_uri(url) let req = request.Request(..req, method: http.Post, body: body) let finch_req = finch.build(req, []) assert Ok(resp) = finch.request(finch_req, server_name()) should.equal(resp.status, 500) should.equal(resp.body, body) } pub fn headers_test() { use <- with_finch() assert Ok(url) = uri.parse(headers_url()) assert Ok(req) = request.from_uri(url) let req = request.Request( ..req, method: http.Delete, headers: [ #("accept", "multipart/form-data"), #("content-type", "formipart/mult-data"), ], ) let finch_req = finch.build(req, []) assert Ok(resp) = finch.request(finch_req, server_name()) should.equal(resp.status, 200) should.be_true(string.contains( resp.body, "#(\"accept\", \"multipart/form-data\")", )) should.be_true(string.contains( resp.body, "#(\"content-type\", \"formipart/mult-data\")", )) should.be_true(list.contains(resp.headers, #("x-token", "token-x"))) } fn ok_url() { base_url <> "/ok" } fn post_url() { base_url <> "/post" } fn headers_url() { base_url <> "/headers" } fn with_finch(test: fn() -> a) { let subject: process.Subject(process.Pid) = process.new_subject() process.start( fn() { assert otp.Ok(child) = start_finch() process.send(subject, child) process.sleep_forever() }, False, ) assert Ok(finch_pid) = process.receive(subject, 1000) let monitor = process.monitor_process(finch_pid) let selector = process.new_selector() |> process.selecting_process_down(monitor, fn(down) { down }) test() process.kill(finch_pid) assert Ok(_) = process.select(selector, 1000) // We need to wait for all the Finch processes to close, sadly didn't find a // better way to do this :/ process.sleep(200) } fn start_finch() -> otp.OnStart { let name = server_name() finch.start_link([otp.Name(name)]) } fn server_name() -> Atom { atom.create_from_string("finch_test_server") } type LogLevel { None } type LoggerOption { Level(LogLevel) } type LoggerOptions = List(LoggerOption) external fn configure_logger(LoggerOptions) -> Nil = "Elixir.Logger" "configure"