
RegistryTest.pudu
Pudu78 lines4.6 KB
1/** @Test.Registry.Suite — building, sharing, reloading, and naming pipelines */2module PuduLangResilience.RegistryTest34import Std.Io as Io5import Std.Option as Option6import Std.Sync as Sync7import Std.Test as Test8import PuduLangResilience.Context as Context9import PuduLangResilience.Pipeline as Pipeline10import PuduLangResilience.Registry as Registry11import PuduLangResilience as Resilience12import PuduLangResilience.Retry as Retry13import PuduLangResilience.Strategy as Strategy141516fn counting(builds: &Sync.Counter) -> Registry.Builder[Int, Str] {17 let counter = *builds18 fn(context: Registry.BuilderContext) -> Array[Strategy.Strategy[Int, Str]] {19 let _counted = Sync.increment(&counter, 1)20 [Retry.strategy(Retry.Options{..Retry.defaults(), name: Some(context.builderName + "-retry"), delay: 0})]21 }22}232425fn main() -> Int {26 let registry: Registry.Registry[Int, Str] = Registry.create()27 let builds = Sync.counter(0)28 let added = Registry.tryAddBuilder(®istry, "orders", counting(&builds))29 let addedAgain = Registry.tryAddBuilder(®istry, "orders", counting(&builds))30 let first = Registry.get(®istry, "orders")31 let second = Registry.get(®istry, "orders")32 let buildsAfterTwoGets = Sync.count(&builds)33 let reloaded = Registry.reload(®istry, "orders")34 let buildsAfterReload = Sync.count(&builds)35 let missing = Registry.get(®istry, "payments")36 let viaGetOrAdd = Registry.getOrAdd(®istry, "payments", counting(&builds))37 let invalidAdded = Registry.tryAddBuilder(®istry, "broken", fn(_context: Registry.BuilderContext) -> Array[Strategy.Strategy[Int, Str]] {38 [Retry.strategy(Retry.Options{..Retry.defaults(), maxRetryAttempts: 0})]39 })40 let broken = Registry.get(®istry, "broken")4142 let named: Registry.Registry[Int, Str] = Registry.createWith(Registry.Options{..Registry.defaults(), builderName: fn(key: Str) -> Str { "svc-" + key }, instanceName: fn(key: Str) -> Option[Str] { Some(key + "-1") }})43 let namedPipeline = Registry.getOrAdd(&named, "users", counting(&Sync.counter(0)))44 let description = match namedPipeline { case Ok(pipeline) => Some(Pipeline.describe(&pipeline)) case Err(_) => None }4546 let calls = Sync.counter(0)47 let ran = match first {48 case Ok(pipeline) => Pipeline.execute(&pipeline, fn(_context: Context.Context) -> Resilience.Outcome[Int, Str] {49 let made = match Sync.increment(&calls, 1) { case Ok(n) => n case Err(_) => 0 }50 if made < 2 { Resilience.raise("once") } else { Ok(made) }51 })52 case Err(problem) => Resilience.raise(Registry.explain(&problem))53 }5455 let checks = Test.suite("Registry", &[56 Test.that("a builder is added for a new key", added),57 Test.not("a second builder for the same key is refused", addedAgain),58 Test.that("the pipeline is found", match (first, second) { case (Ok(_), Ok(_)) => true case _ => false }),59 Test.equals("the pipeline is built once and shared", &buildsAfterTwoGets, &Ok(1)),60 Test.that("a reload builds a new pipeline", match reloaded { case Ok(_) => true case Err(_) => false }),61 Test.equals("a reload runs the builder again", &buildsAfterReload, &Ok(2)),62 Test.equals("an unknown key is not found", &match missing { case Err(problem) => Registry.explain(&problem) case Ok(_) => "" }, &"No pipeline builder is registered for 'payments'."),63 Test.that("getOrAdd registers and builds", match viaGetOrAdd { case Ok(_) => true case Err(_) => false }),64 Test.equals("a registered pipeline runs its strategies", &ran, &Ok(2)),65 Test.that("an invalid builder can be registered", invalidAdded),66 Test.equals("an invalid pipeline is explained", &match broken { case Err(problem) => Registry.explain(&problem) case Ok(_) => "" }, &"The pipeline for 'broken' is invalid: Retry: maxRetryAttempts must be at least 1"),67 Test.equals("tryGet answers nothing for an invalid pipeline", &(Registry.tryGet(®istry, "broken") == None), &true),68 Test.equals("every key with a builder is listed", &Registry.keys(®istry), &["broken", "orders", "payments"]),69 Test.equals("keys become builder and instance names", &Option.map(description, |found: Pipeline.Descriptor| (found.name, found.instance)), &Some((Some("svc-users"), Some("users-1")))),70 Test.equals("the builder sees its names", &Option.map(description, |found: Pipeline.Descriptor| found.strategies.map(|layer: Pipeline.Described| layer.name)), &Some([Some("svc-users-retry")]))71 ])72 let report = Test.run(&checks)73 for failure in Test.failuresOf(&report) {74 let _reported = Io.writeErrorLine(failure)75 }76 Test.report(&report)77}78