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

PoolTest.pudu

Pudu88 lines4.2 KB

GitHub ↗
1/** @Test.Transport.Pool.Suite — leases granted, waited for, returned, and swept */2module PuduLangHttpClient.Transport.PoolTest34import Std.Concurrent.Cancel as Cancel5import Std.Concurrent as Concurrent6import Std.Io as Io7import Std.Net as Net8import Std.Test as Test9import PuduLangHttpClient.Constants.Defaults as Defaults10import PuduLangHttpClient.Domain.Persistence as Persistence11import PuduLangHttpClient.Transport.Pool as Pool12import PuduLangHttpClient.Transport.Wire as Wire1314/// A link that is never used on the wire.15fn link(token: Int) -> Wire.Link { Wire.Plain(Net.Connection{token: token}) }1617/// Whether a lease reuses a connection.18fn isReused(lease: &Result[Pool.Lease, Wire.Fault]) -> Bool {19  match lease {20    case Ok(Pool.Reused(_)) => true21    case _ => false22  }23}2425/// Runs the suite.26fn main() -> Int {27  let forever = Persistence.Limits{lifetime: Defaults.INFINITE, idleTimeout: Defaults.INFINITE}28  let pool = Pool.create(forever, 2)29  let token = Cancel.token()30  let first = Pool.acquire(&pool, "a", &token, None)31  let second = Pool.acquire(&pool, "a", &token, None)32  let full = Pool.acquire(&pool, "a", &Cancel.expiring(20), Some(clock() + 20))33  let otherOrigin = Pool.acquire(&pool, "b", &token, None)34  Pool.release(&pool, "a", link(-1), clock(), true)35  let reused = Pool.acquire(&pool, "a", &token, None)36  Pool.release(&pool, "a", link(-2), clock(), false)37  let afterClosing = Pool.statistics(&pool)38  Pool.forfeit(&pool, "b")39  let afterForfeit = Pool.statistics(&pool)4041  let waiting = Pool.create(forever, 1)42  let _held = Pool.acquire(&waiting, "a", &token, None)43  let _releaser = Concurrent.start(fn() -> () {44      let _slept = Concurrent.sleep(30)45      Pool.release(&waiting, "a", link(-3), clock(), true)46    })47  let waited = Pool.acquire(&waiting, "a", &Cancel.expiring(2000), Some(clock() + 2000))48  let cancelling = Cancel.token()49  let _cancelled = Cancel.cancel(&cancelling, "stop")50  let refused = Pool.acquire(&waiting, "a", &cancelling, None)5152  let expiring = Pool.create(Persistence.Limits{lifetime: Defaults.INFINITE, idleTimeout: 0}, 4)53  let _lease = Pool.acquire(&expiring, "a", &token, None)54  Pool.release(&expiring, "a", link(-4), clock(), true)55  let swept = Pool.acquire(&expiring, "a", &token, None)5657  let closing = Pool.create(forever, 4)58  let _x = Pool.acquire(&closing, "a", &token, None)59  let _y = Pool.acquire(&closing, "a", &token, None)60  Pool.release(&closing, "a", link(-5), clock(), true)61  Pool.close(&closing)62  Pool.release(&closing, "a", link(-6), clock(), true)6364  let checks = Test.suite("Transport.Pool", &[65      Test.equals("an empty pool grants new connections up to the limit", &(first, second), &(Ok(Pool.Fresh), Ok(Pool.Fresh))),66      Test.equals("a full origin makes a request wait until its deadline", &full, &Err(Wire.Stalled)),67      Test.equals("another origin has its own limit", &otherOrigin, &Ok(Pool.Fresh)),68      Test.that("a released connection is reused", isReused(&reused)),69      Test.equals("a connection released as not reusable is closed", &(afterClosing.closed, afterClosing.idle, afterClosing.active), &(1, 0, 2)),70      Test.equals("a forfeited lease is not counted as opened", &(afterForfeit.opened, afterForfeit.active), &(2, 1)),71      Test.that("a waiting request gets the connection released to it", isReused(&waited)),72      Test.equals("a waiting request stops when its token fires", &refused, &Err(Wire.Stalled)),73      Test.equals("an idle connection past its timeout is closed instead of reused", &(swept, Pool.statistics(&expiring).closed), &(Ok(Pool.Fresh), 1)),74      Test.equals("closing a pool closes its idle connections and every later release", &(Pool.statistics(&closing).idle, Pool.statistics(&closing).closed, Pool.isClosed(&closing)), &(0, 2, true)),75      Test.equals("a deadline in the past leaves no budget", &Wire.budget(Some(clock() - 1)), &None),76      Test.equals("no deadline is an unlimited budget", &Wire.budget(None), &Some(Defaults.INFINITE)),77      Test.that("a future deadline leaves what remains of it", match Wire.budget(Some(clock() + 10000)) {78          case Some(left) => left > 9000 && left <= 1000079          case None => false80        })81    ])82  let ran = Test.run(&checks)83  for failure in Test.failuresOf(&ran) {84    let _reported = Io.writeErrorLine(failure)85  }86  Test.report(&ran)87}88