
PlaceholderLiveTest.pudu
Pudu95 lines5.3 KB
1/** @Test.Integration.PlaceholderLive.Suite — the replica checked against the public placeholder service */2module Integration.PlaceholderLiveTest34import Std.Env as Env5import Std.Io as Io6import Std.Json as Json7import Std.Result as Result8import Std.Test as Test9import PuduLangHttpClient.Client as Client10import PuduLangHttpClient.Factory.Builder as Builder11import PuduLangHttpClient.Factory as Factory12import PuduLangHttpClient.Handlers.Resilience as Resilience13import PuduLangHttpClient as HttpClient14import PuduLangHttpClient.Transport as Transport15import Support.Placeholder.Api as Api16import Support.Placeholder.Server as Placeholder171819const PUBLIC: Str = "https://jsonplaceholder.typicode.com/"202122fn counts(api: &Api.Api) -> Array[Int] {23 let sizes: Array[Result[Int, HttpClient.Failure]] = [24 Result.map(Api.list[Api.Post](api, "posts", &[]), |items: Array[Api.Post]| items.length()),25 Result.map(Api.list[Api.Comment](api, "comments", &[]), |items: Array[Api.Comment]| items.length()),26 Result.map(Api.list[Api.Album](api, "albums", &[]), |items: Array[Api.Album]| items.length()),27 Result.map(Api.list[Api.Photo](api, "photos", &[]), |items: Array[Api.Photo]| items.length()),28 Result.map(Api.list[Api.Todo](api, "todos", &[]), |items: Array[Api.Todo]| items.length()),29 Result.map(Api.list[Api.User](api, "users", &[]), |items: Array[Api.User]| items.length())30 ]31 sizes.map(|size: Result[Int, HttpClient.Failure]| Result.unwrapOr(size, -1))32}333435fn owners(api: &Api.Api) -> Array[Int] {36 [37 Result.unwrapOr(Result.map(Api.find[Api.Post](api, "posts", 42), |p: Api.Post| p.userId), -1),38 Result.unwrapOr(Result.map(Api.find[Api.Comment](api, "comments", 42), |c: Api.Comment| c.postId), -1),39 Result.unwrapOr(Result.map(Api.find[Api.Album](api, "albums", 42), |a: Api.Album| a.userId), -1),40 Result.unwrapOr(Result.map(Api.find[Api.Photo](api, "photos", 4242), |p: Api.Photo| p.albumId), -1),41 Result.unwrapOr(Result.map(Api.find[Api.Todo](api, "todos", 142), |t: Api.Todo| t.userId), -1)42 ]43}44454647fn writes(api: &Api.Api) -> (Result[Int, HttpClient.Failure], Result[Str, HttpClient.Failure], Result[Str, HttpClient.Failure], Result[Int, HttpClient.Failure]) {48 (49 Result.map(Api.create(api, "posts", &Api.Post{userId: 1, id: 0, title: "new", body: "b"}), |p: Api.Post| p.id),50 Result.map(Api.replace(api, "posts", 1, &Api.Post{userId: 1, id: 1, title: "replaced", body: "b"}), |p: Api.Post| p.title),51 Result.map(Api.patch[Api.Post](api, "posts", 1, &Json.object(&[("title", Json.Text("patched"))])), |p: Api.Post| p.title),52 Api.remove(api, "posts", 1)53 )54}555657fn main() -> Int {58 let live = Env.variableOr("PUDU_LIVE", "") == "1"59 let reason = "set PUDU_LIVE=1 to check the replica against the public service"60 let replica = Placeholder.start()61 let local = Api.Api{client: Client.pooled(Transport.defaults()).withBaseAddress(replica.base + "/")}62 let resilient = match Resilience.standard() {63 case Ok(built) => built64 case Err(_) => panic("the standard pipeline did not build")65 }66 let factory = match Factory.build([67 Builder.named("public").withBaseAddress(PUBLIC).withTimeout(30000).withHandler(Resilience.handler(resilient)).configureTransport(|options: Transport.Options| options.withDecompression())68 ]) {69 case Ok(built) => built70 case Err(invalid) => panic(Factory.explain(&invalid))71 }72 let remote = Factory.typed(&factory, "public", |client: Client.Client| Api.Api{client: client})73 let localCounts = counts(&local)74 let localOwners = owners(&local)75 let remoteCounts = if live { counts(&remote) } else { [] }76 let remoteOwners = if live { owners(&remote) } else { [] }77 let remoteWrites = if live { Some(writes(&remote)) } else { None }78 let remoteUser: HttpClient.Outcome[Api.User] = if live { Api.find(&remote, "users", 1) } else { HttpClient.invalid("skipped") }79 let localUser: HttpClient.Outcome[Api.User] = Api.find(&local, "users", 1)80 Placeholder.stop(&replica)81 Factory.dispose(&factory)82 let checks = Test.suite("Integration.PlaceholderLive", &[83 Test.equals("the replica holds the public service's counts and owners", &(localCounts, localOwners), &([100, 500, 100, 5000, 200, 10], [5, 9, 5, 85, 8])),84 Test.skipIf(!live, reason, &Test.equals("the public service holds the replica's counts", &remoteCounts, &localCounts)),85 Test.skipIf(!live, reason, &Test.equals("records belong to the same owners in both", &remoteOwners, &localOwners)),86 Test.skipIf(!live, reason, &Test.equals("the first user is the same person in both", &Result.map(remoteUser, |u: Api.User| (u.username, u.address.geo, u.company.name)), &Result.map(localUser, |u: Api.User| (u.username, u.address.geo, u.company.name)))),87 Test.skipIf(!live, reason, &Test.equals("the public service answers every write the replica supports", &remoteWrites, &Some((Ok(101), Ok("replaced"), Ok("patched"), Ok(200)))))88 ])89 let ran = Test.run(&checks)90 for failure in Test.failuresOf(&ran) {91 let _reported = Io.writeErrorLine(failure)92 }93 Test.report(&ran)94}95