Pudu programming language
Menu
Package

@chrismichaelps / pudu-lang-httpclient

Named HTTP clients for Pudu: a client factory, delegating handlers, pooled keep-alive connections, handler lifetimes, logging, and resilience

0.1.1Apache-2.01

InstallClose

HandlerTest.pudu

Pudu47 lines3.0 KB

GitHub ↗
1/** @Test.Handler.Suite — delegating handlers composed around a primary handler */2module PuduLangHttpClient.HandlerTest34import Std.Concurrent.Cancel as Cancel5import Std.Io as Io6import Std.Result as Result7import Std.Test as Test8import PuduLangHttpClient.Handler as Handler9import PuduLangHttpClient as HttpClient10import PuduLangHttpClient.Request as Request11import PuduLangHttpClient.Response as Response1213/// A handler recording its name on the way in and on the way out.14fn tracing(name: Str) -> Handler.Handler {15  fn(request: Request.Request, token: Cancel.Token, next: Handler.Send) -> HttpClient.Outcome[Response.Response] {16    let inbound = request.withHeader("trace", name)17    let response = next(inbound, token) ?18    Ok(response.withHeader("trace", name))19  }20}2122/// A primary handler echoing the request's trace into its response.23fn echo(request: Request.Request, _token: Cancel.Token) -> HttpClient.Outcome[Response.Response] {24  Ok(Response.answer(&request, 200).withText(request.headers.map(|pair: (Str, Str)| pair[1]).join(">")))25}2627/// Runs the suite.28fn main() -> Int {29  let send = Handler.compose(&[tracing("outer"), tracing("middle"), tracing("inner")], echo)30  let outcome = send(Request.get("http://a/"), Cancel.token())31  let refusing = Handler.compose(&[fn(request: Request.Request, _token: Cancel.Token, _next: Handler.Send) -> HttpClient.Outcome[Response.Response] { HttpClient.invalid("refused") }, tracing("never")], echo)32  let changed = Handler.compose(&[Handler.before(|request: Request.Request| request.withHeader("x", "before")), Handler.after(|response: Response.Response| response.withHeader("after", "yes")), Handler.passThrough()], echo)(Request.get("http://a/"), Cancel.token())33  let checks = Test.suite("Handler", &[34      Test.equals("a request passes through the handlers in order", &Result.map(outcome, |r: Response.Response| Result.unwrapOr(Response.text(&r), "")), &Ok("outer>middle>inner")),35      Test.equals("a response comes back through them in reverse", &Result.map(outcome, |r: Response.Response| Response.headerValues(&r, "trace")), &Ok(["inner", "middle", "outer"])),36      Test.equals("a handler may answer without calling the rest", &Result.map(refusing(Request.get("http://a/"), Cancel.token()), |r: Response.Response| r.status.code), &Err(HttpClient.InvalidRequest("refused"))),37      Test.equals("no handlers leave the primary handler alone", &Result.map(Handler.compose(&[], echo)(Request.get("http://a/"), Cancel.token()), |r: Response.Response| r.status.code), &Ok(200)),38      Test.equals("before and after change the request and the response", &Result.map(changed, |r: Response.Response| (Result.unwrapOr(Response.text(&r), ""), Response.header(&r, "after"))), &Ok(("before", Some("yes")))),39      Test.equals("around makes one handler a sender", &Result.map(Handler.around(tracing("only"), echo)(Request.get("http://a/"), Cancel.token()), |r: Response.Response| Result.unwrapOr(Response.text(&r), "")), &Ok("only"))40    ])41  let ran = Test.run(&checks)42  for failure in Test.failuresOf(&ran) {43    let _reported = Io.writeErrorLine(failure)44  }45  Test.report(&ran)46}47