Pudu programming language
Menu
Package

@chrismichaelps / pudu-lang-log

Structured event logging for Pudu: message templates, enrichment, filtering, formatting, and sinks

0.1.0Apache-2.01

InstallClose

CorrelationTest.pudu

Pudu65 lines3.6 KB

GitHub ↗
1/** @Test.Web.Correlation.Suite — one identifier carried across a request */2module PuduLangLog.Web.CorrelationTest34import Std.Http.Server.Route as Route5import Std.Http as Web6import Std.Io as Io7import Std.Map as Map8import Std.Option as Option9import Std.Sync as Sync10import Std.Test as Test11import PuduLangLog.Configuration as Configuration12import PuduLangLog.Event as Event13import PuduLangLog as Log14import PuduLangLog.Logger as Logger15import PuduLangLog.Sinks.Memory as Memory16import PuduLangLog.Value as Value17import PuduLangLog.Web.Correlation as Correlation18import PuduLangLog.Web.RequestLogging as RequestLogging1920/// A routed request with headers.21fn request(headers: Array[(Str, Str)]) -> Route.Request {22  Route.Request{message: Web.Request{..Web.request(Web.Get, "/orders"), headers: headers}, path: "/orders", params: Map.empty(), query: Map.empty(), peer: "127.0.0.1"}23}2425/// A response with headers and no body.26fn answer(headers: Array[(Str, Str)]) -> Web.Response { Web.Response{status: Web.status(200), headers: headers, body: "", binaryBody: None} }2728/// Runs the suite.29fn main() -> Int {30  let fixed = Correlation.Options{..Correlation.defaults(), generate: fn() -> Str { "generated" }}31  let seen = Sync.cell("")32  let handler = fn(incoming: Route.Request) -> Web.Response {33    let _stored = Sync.set(&seen, Option.unwrapOr(Route.header(&incoming, Correlation.HEADER), "missing"))34    answer([])35  }36  let middleware = Correlation.middleware(fixed)37  let brought = middleware(request([("X-Correlation-ID", " abc ")]), handler)38  let broughtSeen = Sync.get(&seen)39  let made = middleware(request([("x-correlation-id", "  ")]), handler)40  let madeSeen = Sync.get(&seen)41  let own = middleware(request([]), fn(_incoming: Route.Request) -> Web.Response { answer([("X-Correlation-Id", "mine")]) })42  let silent = Correlation.middleware(Correlation.Options{..fixed, echo: false})(request([]), handler)43  let memory = Memory.create()44  let logger = Configuration.create().writeTo(Memory.sink(&memory)).createLogger()45  Correlation.loggerFor(&logger, &request([("x-correlation-id", "r1")]), &fixed).information("inside", [])46  Correlation.loggerFor(&logger, &request([]), &fixed).information("outside", [])47  let logging = RequestLogging.middleware(&logger, RequestLogging.Options{..RequestLogging.defaults(), enrich: Correlation.enrich(fixed)})48  let _logged = logging(request([("x-correlation-id", "r2")]), fn(_incoming: Route.Request) -> Web.Response { answer([]) })49  let events = Memory.events(&memory)50  let random = [Correlation.randomIdentifier(), Correlation.randomIdentifier()]51  let checks = Test.suite("Web.Correlation", &[52      Test.equals("a brought identifier reaches the handler as sent and is echoed trimmed", &(broughtSeen, Web.header(&brought.headers, "x-correlation-id")), &(Ok(" abc "), Some("abc"))),53      Test.equals("a blank identifier is replaced by a generated one", &(madeSeen, Web.header(&made.headers, "x-correlation-id")), &(Ok("generated"), Some("generated"))),54      Test.equals("a response's own header is kept", &own.headers, &[("X-Correlation-Id", "mine")]),55      Test.equals("echo can be turned off", &silent.headers, &[]),56      Test.equals("a request logger carries the identifier", &events.map(|event: Log.Event| Event.property(&event, "CorrelationId")), &[Some(Value.text("r1")), None, Some(Value.text("r2"))]),57      Test.that("random identifiers are 32 hexadecimal digits and differ", random[0] != random[1] && random[0].length() == 32 && random[0].chars().filter(|digit: Char| !"0123456789abcdef".contains(digit.toText())).isEmpty())58    ])59  let ran = Test.run(&checks)60  for failure in Test.failuresOf(&ran) {61    let _reported = Io.writeErrorLine(failure)62  }63  Test.report(&ran)64}65