
PoolTest.pudu
Pudu88 lines4.2 KB
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 Wire131415fn link(token: Int) -> Wire.Link { Wire.Plain(Net.Connection{token: token}) }161718fn isReused(lease: &Result[Pool.Lease, Wire.Fault]) -> Bool {19 match lease {20 case Ok(Pool.Reused(_)) => true21 case _ => false22 }23}242526fn 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