Estou escrevendo testes de integração de código skunk com postgres usando scala-test-containers , munit e munit-cats-effect , usando Mill e Scala 3. Sou novo no Cats Effect .
A configuração que estou tentando alcançar é:
- O conjunto de testes inicia o contêiner postgres e cria a sessão skunk uma vez para todo o conjunto (e interrompe o contêiner quando o conjunto é concluído).
- Cada teste ocorre dentro de sua própria transação de banco de dados skunk que é revertida para manter os testes isolados.
Abaixo está o código até agora, com o qual o compilador está ok, exceto pela chamada para rollback
, que requer um skunk.util.Origin
. Não vejo nenhuma referência a esse tipo na documentação do skunk e não consigo descobrir como devo trazê-lo para o escopo.
Como posso fazer a chamada para rollback
compilar neste código? Onde está o Origin implícito ausente?
import cats.effect.IO
import munit.CatsEffectSuite
import org.testcontainers.utility.DockerImageName
import cats.effect.kernel.Resource
import skunk.*
import skunk.implicits.*
import natchez.Trace.Implicits.noop
import munit.catseffect.IOFixture
import cats.implicits.catsSyntaxFlatMapOps
val container: Resource[IO, PostgreSQLContainer] =
Resource.make
(for {
c <- IO(PostgreSQLContainer(
DockerImageName.parse("postgres:17-alpine")
))
_ <- IO.blocking(c.start())
} yield c)
(c => IO.blocking(c.stop()))
val sessionResource: Resource[IO, Session[IO]] =
container.flatMap { c =>
Session.single[IO](
host = "localhost",
port = 5432,
user = c.username,
password = Some(c.password),
database = c.databaseName
)
}
def useWithRollback[T](s: Session[IO])(f: Transaction[IO] => IO[T]) =
s.transaction.use { xa =>
for {
result <- f(xa)
_ <- xa.rollback() // fails compilation: needs implicit skunk.util.Origin
} yield result
}
class PgIntegrationTests extends CatsEffectSuite:
val session = ResourceSuiteLocalFixture(
"skunk session",
sessionResource
)
override def munitFixtures = List(session)
def withDb[T](f: Transaction[IO] => IO[T]) =
useWithRollback(session())(f)
A ideia é que um teste seria algo como
test("something") {
withDb { xa =>
for {
result <- callMyCode(xa)
_ <- assertIO(result, <expected result>)
} yield ()
}
}
A compilação acima falha, useWithRollback
com
[error] 41 | _ <- xa.rollback()
[error] | ^^^^^^^^^^^
[error] | None of the overloaded alternatives of method rollback in trait Transaction with types
[error] | (implicit o: skunk.util.Origin): cats.effect.IO[skunk.data.Completion]
[error] | (savepoint: xa.Savepoint)(implicit o: skunk.util.Origin): cats.effect.IO[skunk.data.Completion]
[error] | match arguments ()
do qual eu deduzo que ele está procurando por um Origin
no escopo. Como posso trazer isso Origin
para o escopo? Por que a página skunk Transaction (linkada acima) não tem esse problema onde ele chama rollback
em seu exemplo?
Obrigado pelo seu tempo.
PS: O arquivo de construção do Mill build.sc
:
import mill._, scalalib._
object devmap extends ScalaModule {
def scalaVersion = "3.5.1"
def ivyDeps = Agg(
ivy"org.tpolecat::skunk-core:0.6.4",
ivy"org.typelevel::cats-effect:3.5.7"
)
object test extends ScalaTests with TestModule.Munit {
def ivyDeps = Agg(
ivy"org.scalameta::munit::0.7.29",
ivy"org.typelevel::munit-cats-effect:2.0.0",
ivy"com.dimafeng::testcontainers-scala-postgresql:0.41.5",
ivy"org.postgresql:postgresql:42.7.4",
ivy"com.lihaoyi::pprint:0.9.0"
)
}
}