Last active
April 5, 2025 07:36
-
-
Save dacr/4471ee84b22d6af75bac81efd8a574e1 to your computer and use it in GitHub Desktop.
Chronos API tests / published by https://github.com/dacr/code-examples-manager #91025af9-38bd-4b7a-8b6c-7997162400fc/7c606d3a76f46c2073fd66037d6a53567ac1361a
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env -S scala-cli test -S 3 | |
// summary : Chronos API tests | |
// keywords : scala, cats, sttp, chronos, test | |
// publish : gist | |
// authors : David Crosson | |
// license : Apache NON-AI License Version 2.0 (https://raw.githubusercontent.com/non-ai-licenses/non-ai-licenses/main/NON-AI-APACHE2) | |
// id : 91025af9-38bd-4b7a-8b6c-7997162400fc | |
// created-on : 2025-01-11T00:22:40+01:00 | |
// managed-by : https://github.com/dacr/code-examples-manager | |
// run-with : scala-cli test $file | |
// test-with : curl http://127.0.0.1:8080/chronos | |
// --------------------- | |
//> using scala 3.6.4 | |
//> using objectWrapper | |
////> using platform native | |
////> using nativeVersion 0.5.7 | |
//> using dep com.softwaremill.sttp.client4::circe:4.0.0-RC3 | |
//> using dep com.softwaremill.sttp.client4::cats:4.0.0-RC3 | |
//> using dep org.typelevel::cats-effect:3.6.0 | |
//> using dep io.circe::circe-generic:0.14.12 | |
//> using dep org.typelevel::munit-cats-effect-3:1.0.7 | |
// --------------------- | |
import io.circe.generic.auto.* | |
import io.circe.* | |
import io.circe.parser.* | |
import io.circe.syntax.* | |
import sttp.client4.* | |
import sttp.client4.circe.* | |
import sttp.client4.httpclient.cats.HttpClientCatsBackend | |
import HttpClientCatsBackend.resource | |
import cats.effect.{IO, SyncIO} | |
import munit.CatsEffectSuite | |
import java.time.{Instant, OffsetDateTime} | |
import java.util.UUID | |
object Model { | |
type CompetitorId = UUID | |
type ChronosId = UUID | |
// ------------------------------------------------------------------------------------------------------------------- | |
case class ChronosSpec( | |
name: String, | |
description: String | |
) | |
// ------------------------------------------------------------------------------------------------------------------- | |
case class CompetitorSpec( | |
firstName: String, | |
lastName: String, | |
birthDate: OffsetDateTime | |
) | |
// ------------------------------------------------------------------------------------------------------------------- | |
case class TimerSpec( | |
name: String | |
) | |
// ------------------------------------------------------------------------------------------------------------------- | |
case class Chronos( | |
id: ChronosId, | |
name: String, | |
description: String, | |
created: Instant | |
) | |
// ------------------------------------------------------------------------------------------------------------------- | |
case class Competitor( | |
id: CompetitorId, | |
firstName: String, | |
lastName: String, | |
birthDate: OffsetDateTime | |
) | |
// ------------------------------------------------------------------------------------------------------------------- | |
enum TimingCategory { | |
case Start | |
case Step | |
case End | |
} | |
case class Timing( | |
category: TimingCategory, | |
timestamp: Instant | |
) | |
// ------------------------------------------------------------------------------------------------------------------- | |
} | |
class ClassicTests extends CatsEffectSuite { | |
import Model.* | |
given Encoder[TimingCategory] = Encoder[String].contramap(_.toString) | |
given Decoder[TimingCategory] = Decoder[String].emap(s => Right(TimingCategory.valueOf(s))) // TODO manage left case | |
val baseAPI = "http://127.0.0.1:8080" | |
// ----------------------------------------------------------------------------------------------- | |
test("List chronos") { | |
resource[IO]().use { backend => | |
for { | |
chronos <- | |
quickRequest | |
.get(uri"$baseAPI/chronos") | |
.response(asJson[List[Chronos]]) | |
.send(backend) | |
} yield assertEquals(chronos.code.code, 200) | |
} | |
} | |
// ----------------------------------------------------------------------------------------------- | |
test("Create, read, update, delete a chronos") { | |
resource[IO]().use { backend => | |
for { | |
randName <- IO.randomUUID.map(uuid => s"Chronos $uuid") | |
chronos <- | |
quickRequest | |
.post(uri"$baseAPI/chronos") | |
.body(ChronosSpec(randName, s"$randName description").asJson.noSpaces) | |
.response(asJson[Chronos]) | |
.send(backend) | |
.flatMap(response => IO.fromEither(response.body)) | |
gottenChronos <- | |
quickRequest | |
.get(uri"$baseAPI/chronos/${chronos.id}") | |
.response(asJson[Chronos]) | |
.send(backend) | |
.flatMap(response => IO.fromEither(response.body)) | |
_ <- | |
quickRequest | |
.put(uri"$baseAPI/chronos/${chronos.id}") | |
.body(ChronosSpec(randName, s"$randName updated description").asJson.noSpaces) | |
.send(backend) | |
updatedChronos <- | |
quickRequest | |
.get(uri"$baseAPI/chronos/${chronos.id}") | |
.response(asJson[Chronos]) | |
.send(backend) | |
.flatMap(response => IO.fromEither(response.body)) | |
responseDelete <- | |
quickRequest | |
.delete(uri"$baseAPI/chronos/${chronos.id}") | |
.send(backend) | |
resultAfterDelete <- | |
quickRequest | |
.get(uri"$baseAPI/chronos/${chronos.id}") | |
.response(asJson[Chronos]) | |
.send(backend) | |
} yield { | |
assertEquals(chronos, gottenChronos) | |
assertEquals(updatedChronos.description, s"$randName updated description") | |
assert(resultAfterDelete.code.code == 404) | |
} | |
} | |
} | |
// ----------------------------------------------------------------------------------------------- | |
test("List Competitors") { | |
resource[IO]().use { backend => | |
for { | |
randName <- IO.randomUUID.map(uuid => s"Chronos $uuid") | |
chronos <- | |
quickRequest | |
.post(uri"$baseAPI/chronos") | |
.body(ChronosSpec(randName, s"$randName description").asJson.noSpaces) | |
.response(asJson[Chronos]) | |
.send(backend) | |
.flatMap(response => IO.fromEither(response.body)) | |
competitors <- | |
quickRequest | |
.get(uri"$baseAPI/chronos/${chronos.id}/competitor") | |
.response(asJson[List[Competitor]]) | |
.send(backend) | |
} yield assertEquals(competitors.code.code, 200) | |
} | |
} | |
// ----------------------------------------------------------------------------------------------- | |
test("Create, read, update, delete a competitor") { | |
resource[IO]().use { backend => | |
for { | |
randName <- IO.randomUUID.map(uuid => s"Chronos $uuid") | |
randFirstName <- IO.randomUUID.map(uuid => s"Joe-$uuid") | |
chronos <- | |
quickRequest | |
.post(uri"$baseAPI/chronos") | |
.body(ChronosSpec(randName, s"$randName description").asJson.noSpaces) | |
.response(asJson[Chronos]) | |
.send(backend) | |
.flatMap(response => IO.fromEither(response.body)) | |
competitor <- | |
quickRequest | |
.post(uri"$baseAPI/chronos/${chronos.id}/competitor") | |
.body(CompetitorSpec(randFirstName, "doe", OffsetDateTime.parse("1942-01-01T00:00:00Z")).asJson.noSpaces) | |
.response(asJson[Competitor]) | |
.send(backend) | |
.flatMap(response => IO.fromEither(response.body)) | |
gottenCompetitor <- | |
quickRequest | |
.get(uri"$baseAPI/chronos/${chronos.id}/competitor/${competitor.id}") | |
.response(asJson[Competitor]) | |
.send(backend) | |
.flatMap(response => IO.fromEither(response.body)) | |
_ <- | |
quickRequest | |
.put(uri"$baseAPI/chronos/${chronos.id}/competitor/${competitor.id}") | |
.body(CompetitorSpec(s"$randFirstName-updated", competitor.lastName, competitor.birthDate).asJson.noSpaces) | |
.send(backend) | |
updatedCompetitor <- | |
quickRequest | |
.get(uri"$baseAPI/chronos/${chronos.id}/competitor/${competitor.id}") | |
.response(asJson[Competitor]) | |
.send(backend) | |
.flatMap(response => IO.fromEither(response.body)) | |
responseDelete <- | |
quickRequest | |
.delete(uri"$baseAPI/chronos/${chronos.id}/competitor/${competitor.id}") | |
.send(backend) | |
resultAfterDelete <- | |
quickRequest | |
.get(uri"$baseAPI/chronos/${chronos.id}/competitor/${competitor.id}") | |
.response(asJson[Competitor]) | |
.send(backend) | |
} yield { | |
assertEquals(competitor, gottenCompetitor) | |
assert(updatedCompetitor.firstName.contains("updated")) | |
assert(resultAfterDelete.code.code == 404) | |
} | |
} | |
} | |
// ----------------------------------------------------------------------------------------------- | |
test("Take timings of a competitor ") { | |
resource[IO]().use { backend => | |
for { | |
randName <- IO.randomUUID.map(uuid => s"Chronos $uuid") | |
chronos <- | |
quickRequest | |
.post(uri"$baseAPI/chronos") | |
.body(ChronosSpec(randName, s"$randName description").asJson.noSpaces) | |
.response(asJson[Chronos]) | |
.send(backend) | |
.flatMap(response => IO.fromEither(response.body)) | |
competitor <- | |
quickRequest | |
.post(uri"$baseAPI/chronos/${chronos.id}/competitor") | |
.body(CompetitorSpec("john", "doe", OffsetDateTime.parse("1942-01-01T00:00:00Z")).asJson.noSpaces) | |
.response(asJson[Competitor]) | |
.send(backend) | |
.flatMap(response => IO.fromEither(response.body)) | |
timingStart <- | |
quickRequest | |
.put(uri"$baseAPI/chronos/${chronos.id}/competitor/${competitor.id}/timings?Category=${TimingCategory.Start}") | |
.response(asJson[Timing]) | |
.send(backend) | |
.flatMap(response => IO.fromEither(response.body)) | |
timingEnd <- | |
quickRequest | |
.put(uri"$baseAPI/chronos/${chronos.id}/competitor/${competitor.id}/timings?Category=${TimingCategory.End}") | |
.response(asJson[Timing]) | |
.send(backend) | |
.flatMap(response => IO.fromEither(response.body)) | |
timings <- | |
quickRequest | |
.get(uri"$baseAPI/chronos/${chronos.id}/competitor/${competitor.id}/timings") | |
.response(asJson[List[Timing]]) | |
.send(backend) | |
.flatMap(response => IO.fromEither(response.body)) | |
} yield { | |
assert(timings.size == 2) | |
} | |
} | |
} | |
// ----------------------------------------------------------------------------------------------- | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment