-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Small fix on exception handling (on rollback error). Adds tests.
- Loading branch information
1 parent
1910143
commit a143cb5
Showing
3 changed files
with
187 additions
and
6 deletions.
There are no files selected for viewing
This file contains 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
125 changes: 125 additions & 0 deletions
125
core/src/test/scala/io/github/gaelrenoux/tranzactio/ConnectionSourceTest.scala
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
package io.github.gaelrenoux.tranzactio | ||
|
||
import zio.test._ | ||
import zio.{test => _, _} | ||
|
||
import java.sql.Connection | ||
|
||
|
||
object ConnectionSourceTest extends ZIOSpec[TestEnvironment] { | ||
type Env = TestEnvironment | ||
type MySpec = Spec[Env, Any] | ||
|
||
implicit private val errorStrategies: ErrorStrategies = ErrorStrategies.Nothing | ||
|
||
// TODO add aspect to timeout tests to 5 seconds | ||
|
||
override def bootstrap: ZLayer[Any, Any, Env] = testEnvironment | ||
|
||
val connectionCountSql = "select count(*) from information_schema.sessions" | ||
|
||
def connectionCountQuery(c: Connection): ZIO[Any, Throwable, Int] = ZIO.attemptBlocking { | ||
val stmt = c.prepareStatement(connectionCountSql) | ||
try { | ||
val rs = stmt.executeQuery() | ||
rs.next() | ||
val count = rs.getInt(1) | ||
rs.close() | ||
count | ||
} finally { | ||
stmt.close() | ||
} | ||
} | ||
|
||
def spec: MySpec = suite("Single connection ConnectionSource Tests")( | ||
testRunTransactionFailureOnOpen, | ||
testRunTransactionFailureOnAutoCommit, | ||
testRunTransactionFailureOnCommit, | ||
testRunTransactionFailureOnCommitAfterFailure, | ||
testRunTransactionFailureOnRollback, | ||
testRunTransactionFailureOnClose, | ||
testRunAutoCommitFailureOnOpen, | ||
testRunAutoCommitFailureOnAutoCommit, | ||
testRunAutoCommitFailureOnClose | ||
) | ||
|
||
private val testRunTransactionFailureOnOpen = test("runTransaction failure > on open") { | ||
val cs = new FailingConnectionSource(errorStrategies)(failOnOpen = true) | ||
val zio: ZIO[Any, Either[DbException, Throwable], Int] = cs.runTransaction(connectionCountQuery) | ||
zio.flip.map { e => | ||
assertTrue(e == Left(DbException.Wrapped(FailingConnectionSource.OpenException))) | ||
} | ||
} | ||
|
||
private val testRunTransactionFailureOnAutoCommit = test("runTransaction failure > on auto-commit") { | ||
val cs = new FailingConnectionSource(errorStrategies)(failOnAutoCommit = true) | ||
val zio: ZIO[Any, Either[DbException, Throwable], Int] = cs.runTransaction(connectionCountQuery) | ||
zio.flip.map { e => | ||
assertTrue(e == Left(DbException.Wrapped(FailingConnectionSource.AutoCommitException))) | ||
} | ||
} | ||
|
||
private val testRunTransactionFailureOnCommit = test("runTransaction failure > on commit") { | ||
val cs = new FailingConnectionSource(errorStrategies)(failOnCommit = true) | ||
val zio: ZIO[Any, Either[DbException, Throwable], Int] = cs.runTransaction(connectionCountQuery) | ||
zio.flip.map { e => | ||
assertTrue(e == Left(DbException.Wrapped(FailingConnectionSource.CommitException))) | ||
} | ||
} | ||
|
||
private val testRunTransactionFailureOnCommitAfterFailure = test("runTransaction failure > on commit (after failure)") { | ||
val cs = new FailingConnectionSource(errorStrategies)(failOnCommit = true) | ||
val zio: ZIO[Any, Either[DbException, String], Int] = cs.runTransaction(_ => ZIO.fail("Not a good query"), commitOnFailure = true) | ||
zio.cause.map { | ||
case Cause.Both(Cause.Fail(left, _), Cause.Fail(right, _)) => | ||
assertTrue( | ||
left == Left(DbException.Wrapped(FailingConnectionSource.CommitException)), | ||
right == Right("Not a good query") | ||
) | ||
} | ||
} | ||
|
||
private val testRunTransactionFailureOnRollback = test("runTransaction failure > on rollback") { | ||
val cs = new FailingConnectionSource(errorStrategies)(failOnRollback = true) | ||
val zio: ZIO[Any, Either[DbException, String], Int] = cs.runTransaction(_ => ZIO.fail("Not a good query")) | ||
zio.cause.map { | ||
case Cause.Both(Cause.Fail(left, _), Cause.Fail(right, _)) => | ||
assertTrue( | ||
left == Left(DbException.Wrapped(FailingConnectionSource.RollbackException)), | ||
right == Right("Not a good query") | ||
) | ||
} | ||
} | ||
|
||
private val testRunTransactionFailureOnClose = test("runTransaction failure > on close") { | ||
val cs = new FailingConnectionSource(errorStrategies)(failOnClose = true) | ||
val zio: ZIO[Any, Either[DbException, Throwable], Int] = cs.runTransaction(connectionCountQuery) | ||
zio.cause.map { | ||
case Cause.Die(ex, _) => assertTrue(ex == DbException.Wrapped(FailingConnectionSource.CloseException)) | ||
} | ||
} | ||
|
||
private val testRunAutoCommitFailureOnOpen = test("runAutoCommit failure > on open") { | ||
val cs = new FailingConnectionSource(errorStrategies)(failOnOpen = true) | ||
val zio: ZIO[Any, Either[DbException, Throwable], Int] = cs.runAutoCommit(connectionCountQuery) | ||
zio.flip.map { e => | ||
assertTrue(e == Left(DbException.Wrapped(FailingConnectionSource.OpenException))) | ||
} | ||
} | ||
|
||
private val testRunAutoCommitFailureOnAutoCommit = test("runAutoCommit failure > on auto-commit") { | ||
val cs = new FailingConnectionSource(errorStrategies)(failOnAutoCommit = true) | ||
val zio: ZIO[Any, Either[DbException, Throwable], Int] = cs.runAutoCommit(connectionCountQuery) | ||
zio.flip.map { e => | ||
assertTrue(e == Left(DbException.Wrapped(FailingConnectionSource.AutoCommitException))) | ||
} | ||
} | ||
|
||
private val testRunAutoCommitFailureOnClose = test("runAutoCommit failure > on close") { | ||
val cs = new FailingConnectionSource(errorStrategies)(failOnClose = true) | ||
val zio: ZIO[Any, Either[DbException, Throwable], Int] = cs.runAutoCommit(connectionCountQuery) | ||
zio.cause.map { | ||
case Cause.Die(ex, _) => assertTrue(ex == DbException.Wrapped(FailingConnectionSource.CloseException)) | ||
} | ||
} | ||
} |
56 changes: 56 additions & 0 deletions
56
core/src/test/scala/io/github/gaelrenoux/tranzactio/FailingConnectionSource.scala
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package io.github.gaelrenoux.tranzactio | ||
|
||
import zio.{Task, Trace, ZIO} | ||
|
||
import java.sql.{Connection, DriverManager} | ||
import java.util.UUID | ||
|
||
/** A ConnectionSource that fails on some operations */ | ||
class FailingConnectionSource(defaultErrorStrategies: ErrorStrategiesRef)( | ||
failOnOpen: Boolean = false, | ||
failOnAutoCommit: Boolean = false, | ||
failOnCommit: Boolean = false, | ||
failOnRollback: Boolean = false, | ||
failOnClose: Boolean = false | ||
) extends ConnectionSource.ServiceBase(defaultErrorStrategies) { | ||
|
||
import FailingConnectionSource._ | ||
|
||
override protected def getConnection(implicit trace: Trace): Task[Connection] = ZIO.attemptBlocking { | ||
val uuid = UUID.randomUUID().toString | ||
DriverManager.getConnection(s"jdbc:h2:mem:$uuid;DB_CLOSE_DELAY=10", "sa", "sa") | ||
} | ||
|
||
override def openConnection(implicit errorStrategies: ErrorStrategiesRef, trace: Trace): ZIO[Any, DbException, Connection] = | ||
if (failOnOpen) ZIO.fail(DbException.Wrapped(OpenException)) | ||
else super.openConnection | ||
|
||
override def setAutoCommit(c: => Connection, autoCommit: => Boolean)(implicit errorStrategies: ErrorStrategiesRef, trace: Trace): ZIO[Any, DbException, Unit] = { | ||
if (failOnAutoCommit) ZIO.fail(DbException.Wrapped(AutoCommitException)) | ||
else super.setAutoCommit(c, autoCommit) | ||
} | ||
|
||
override def commitConnection(c: => Connection)(implicit errorStrategies: ErrorStrategiesRef, trace: Trace): ZIO[Any, DbException, Unit] = | ||
if (failOnCommit) ZIO.fail(DbException.Wrapped(CommitException)) | ||
else super.commitConnection(c) | ||
|
||
override def rollbackConnection(c: => Connection)(implicit errorStrategies: ErrorStrategiesRef, trace: Trace): ZIO[Any, DbException, Unit] = | ||
if (failOnRollback) ZIO.fail(DbException.Wrapped(RollbackException)) | ||
else super.rollbackConnection(c) | ||
|
||
override def closeConnection(c: => Connection)(implicit errorStrategies: ErrorStrategiesRef, trace: Trace): ZIO[Any, DbException, Unit] = | ||
if (failOnClose) ZIO.fail(DbException.Wrapped(CloseException)) | ||
else super.closeConnection(c) | ||
} | ||
|
||
object FailingConnectionSource { | ||
case object OpenException extends RuntimeException("Oops my connection") | ||
|
||
case object AutoCommitException extends RuntimeException("Oops my auto-commit") | ||
|
||
case object CommitException extends RuntimeException("Oops my commit") | ||
|
||
case object RollbackException extends RuntimeException("Oops my rollback") | ||
|
||
case object CloseException extends RuntimeException("Oops my closing") | ||
} |