Skip to content

Instantly share code, notes, and snippets.

@FloWi
Last active February 14, 2018 18:20
Show Gist options
  • Save FloWi/23d5603fd951e0df714ed6f545b3dd09 to your computer and use it in GitHub Desktop.
Save FloWi/23d5603fd951e0df714ed6f545b3dd09 to your computer and use it in GitHub Desktop.
package doobietest
import com.zaxxer.hikari.{HikariConfig, HikariDataSource}
import doobie.hikari.HikariTransactor
import monix.eval.Task
import org.scalatest.{BeforeAndAfterEach, FunSuite, Matchers}
import scala.concurrent.Await
import scala.concurrent.duration.{FiniteDuration, _}
class MatViewSpec extends FunSuite with BeforeAndAfterEach with Matchers {
import doobie._
import doobie.implicits._
import monix.execution.Scheduler.Implicits.global
val tx = newPostgresHikariTransactor(host = "localhost", databaseName = "postgres", user = "postgres", password = "postgres")
override protected def beforeEach(): Unit = {
val dropFragment = fr"DROP MATERIALIZED VIEW IF EXISTS my_materialized_view"
val createFragment =
fr"""
CREATE MATERIALIZED VIEW my_materialized_view
AS
SELECT 42 AS magic_number
WITH NO DATA
"""
val program = dropFragment
.update
.run
.flatMap { _ =>
createFragment
.update
.run
}.transact(tx)
Await.ready(program.runAsync, 1.second)
}
test("should refresh the materialized view non-concurrently if it hasn't been populated before") {
Await.result(refreshMaterializedViewConcurrentlySafely(Fragment.const("my_materialized_view"), tx).runAsync, 2.seconds)
Await.result(fr"SELECT magic_number FROM my_materialized_view".query[Int].unique.transact(tx).runAsync, 1.second) shouldBe 42
}
/**
* Tries to refresh a materialized view concurrently. If this doesn't succeed (e.g. not poplated yet) it performs a non-concurrent refresh.
*/
def refreshMaterializedViewConcurrentlySafely(viewName: Fragment, tx: Transactor[Task]): Task[Int] = {
concurrentStmt(viewName)
.exceptSql {
case e: java.sql.SQLException if e.getMessage.toLowerCase contains "concurrently cannot be used when the materialized view is not populated" =>
Console.err.println("can't update materialized view concurrently - trying non-concurrently", e)
nonConcurrentStmt(viewName)
case e: Throwable =>
Console.err.println("why am I here?", e)
???
}
.transact(tx)
}
def concurrentStmt(viewName: Fragment): ConnectionIO[Int] = (fr"REFRESH MATERIALIZED VIEW CONCURRENTLY " ++ viewName).update.run
def nonConcurrentStmt(viewName: Fragment): ConnectionIO[Int] = (fr"REFRESH MATERIALIZED VIEW " ++ viewName).update.run
def newPostgresHikariTransactor(host: String,
databaseName: String,
user: String,
password: String,
poolName: Option[String] = None,
maximumPoolSize: Option[Int] = None,
readOnlyPool: Boolean = false,
leakDetectionThreshold: Option[FiniteDuration] = None
): HikariTransactor[Task] = {
val datasource = newHikariDataSource(
host,
user = user,
password = password,
databaseName = databaseName,
poolName = poolName,
maximumPoolSize = maximumPoolSize,
readOnlyPool = readOnlyPool,
leakDetectionThreshold = leakDetectionThreshold
)
HikariTransactor[Task](datasource)
}
def newHikariDataSource(server: String,
port: Int = 5432,
user: String,
password: String,
databaseName: String,
poolName: Option[String] = None,
maximumPoolSize: Option[Int] = None,
readOnlyPool: Boolean = false,
leakDetectionThreshold: Option[FiniteDuration] = Some(10.seconds)): HikariDataSource = {
val config = new HikariConfig
config.setDataSourceClassName("org.postgresql.ds.PGSimpleDataSource")
config.addDataSourceProperty("serverName", server)
config.addDataSourceProperty("portNumber", port)
config.addDataSourceProperty("user", user)
config.addDataSourceProperty("password", password)
config.addDataSourceProperty("databaseName", databaseName)
poolName.foreach(config.setPoolName)
maximumPoolSize.foreach(config.setMaximumPoolSize)
config.setReadOnly(readOnlyPool)
leakDetectionThreshold.foreach { threshold => config.setLeakDetectionThreshold(threshold.toMillis) }
new HikariDataSource(config)
}
}
19:19:35.603 [pool-1-thread-1] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
19:19:35.722 [pool-1-thread-1] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
[info] MatViewSpec:
19:19:37.610 [pool-1-thread-1-ScalaTest-running-MatViewSpec] WARN c.zaxxer.hikari.pool.ProxyConnection - HikariPool-1 - Connection org.postgresql.jdbc.PgConnection@6b79cdd5 marked as broken because of SQLSTATE(0A000), ErrorCode(0)
org.postgresql.util.PSQLException: ERROR: CONCURRENTLY cannot be used when the materialized view is not populated
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2422)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2167)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:306)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:441)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:365)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:155)
at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:132)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)
at doobie.free.KleisliInterpreter$PreparedStatementInterpreter.$anonfun$executeUpdate$5(kleisliinterpreter.scala:772)
at doobie.free.KleisliInterpreter$PreparedStatementInterpreter.$anonfun$executeUpdate$5$adapted(kleisliinterpreter.scala:772)
at doobie.free.KleisliInterpreter.$anonfun$primitive$2(kleisliinterpreter.scala:99)
at monix.eval.internal.TaskRunLoop$.startFuture(TaskRunLoop.scala:379)
at monix.eval.Task.runAsync(Task.scala:303)
at doobietest.MatViewSpec.$anonfun$new$1(MatViewSpec.scala:44)
at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
at org.scalatest.Transformer.apply(Transformer.scala:22)
at org.scalatest.Transformer.apply(Transformer.scala:20)
at org.scalatest.FunSuiteLike$$anon$1.apply(FunSuiteLike.scala:186)
at org.scalatest.TestSuite.withFixture(TestSuite.scala:196)
at org.scalatest.TestSuite.withFixture$(TestSuite.scala:195)
at org.scalatest.FunSuite.withFixture(FunSuite.scala:1560)
at org.scalatest.FunSuiteLike.invokeWithFixture$1(FunSuiteLike.scala:184)
at org.scalatest.FunSuiteLike.$anonfun$runTest$1(FunSuiteLike.scala:196)
at org.scalatest.SuperEngine.runTestImpl(Engine.scala:289)
at org.scalatest.FunSuiteLike.runTest(FunSuiteLike.scala:196)
at org.scalatest.FunSuiteLike.runTest$(FunSuiteLike.scala:178)
at doobietest.MatViewSpec.org$scalatest$BeforeAndAfterEach$$super$runTest(MatViewSpec.scala:11)
at org.scalatest.BeforeAndAfterEach.runTest(BeforeAndAfterEach.scala:221)
at org.scalatest.BeforeAndAfterEach.runTest$(BeforeAndAfterEach.scala:214)
at doobietest.MatViewSpec.runTest(MatViewSpec.scala:11)
at org.scalatest.FunSuiteLike.$anonfun$runTests$1(FunSuiteLike.scala:229)
at org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:396)
at scala.collection.immutable.List.foreach(List.scala:389)
at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:384)
at org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:379)
at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:461)
at org.scalatest.FunSuiteLike.runTests(FunSuiteLike.scala:229)
at org.scalatest.FunSuiteLike.runTests$(FunSuiteLike.scala:228)
at org.scalatest.FunSuite.runTests(FunSuite.scala:1560)
at org.scalatest.Suite.run(Suite.scala:1147)
at org.scalatest.Suite.run$(Suite.scala:1129)
at org.scalatest.FunSuite.org$scalatest$FunSuiteLike$$super$run(FunSuite.scala:1560)
at org.scalatest.FunSuiteLike.$anonfun$run$1(FunSuiteLike.scala:233)
at org.scalatest.SuperEngine.runImpl(Engine.scala:521)
at org.scalatest.FunSuiteLike.run(FunSuiteLike.scala:233)
at org.scalatest.FunSuiteLike.run$(FunSuiteLike.scala:232)
at org.scalatest.FunSuite.run(FunSuite.scala:1560)
at org.scalatest.tools.Framework.org$scalatest$tools$Framework$$runSuite(Framework.scala:314)
at org.scalatest.tools.Framework$ScalaTestTask.execute(Framework.scala:507)
at sbt.ForkMain$Run$2.call(ForkMain.java:296)
at sbt.ForkMain$Run$2.call(ForkMain.java:286)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
(can't update materialized view concurrently - trying non-concurrently,org.postgresql.util.PSQLException: ERROR: CONCURRENTLY cannot be used when the materialized view is not populated)
[info] - should refresh the materialized view non-concurrently if it hasn't been populated before *** FAILED *** (1 second, 231 milliseconds)
[info] java.sql.SQLException: Connection is closed
[info] at com.zaxxer.hikari.pool.ProxyConnection$ClosedConnection.lambda$getClosedConnection$0(ProxyConnection.java:490)
[info] at com.sun.proxy.$Proxy4.rollback(Unknown Source)
[info] at com.zaxxer.hikari.pool.ProxyConnection.rollback(ProxyConnection.java:377)
[info] at com.zaxxer.hikari.pool.HikariProxyConnection.rollback(HikariProxyConnection.java)
[info] at doobie.free.KleisliInterpreter$ConnectionInterpreter.$anonfun$rollback$1(kleisliinterpreter.scala:643)
[info] at doobie.free.KleisliInterpreter$ConnectionInterpreter.$anonfun$rollback$1$adapted(kleisliinterpreter.scala:643)
[info] at doobie.free.KleisliInterpreter.$anonfun$primitive$2(kleisliinterpreter.scala:99)
[info] at monix.eval.internal.TaskRunLoop$.startFuture(TaskRunLoop.scala:379)
[info] at monix.eval.Task.runAsync(Task.scala:303)
[info] at doobietest.MatViewSpec.$anonfun$new$1(MatViewSpec.scala:44)
[info] at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
[info] at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
[info] at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
[info] at org.scalatest.Transformer.apply(Transformer.scala:22)
[info] at org.scalatest.Transformer.apply(Transformer.scala:20)
[info] at org.scalatest.FunSuiteLike$$anon$1.apply(FunSuiteLike.scala:186)
[info] at org.scalatest.TestSuite.withFixture(TestSuite.scala:196)
[info] at org.scalatest.TestSuite.withFixture$(TestSuite.scala:195)
[info] at org.scalatest.FunSuite.withFixture(FunSuite.scala:1560)
[info] at org.scalatest.FunSuiteLike.invokeWithFixture$1(FunSuiteLike.scala:184)
[info] at org.scalatest.FunSuiteLike.$anonfun$runTest$1(FunSuiteLike.scala:196)
[info] at org.scalatest.SuperEngine.runTestImpl(Engine.scala:289)
[info] at org.scalatest.FunSuiteLike.runTest(FunSuiteLike.scala:196)
[info] at org.scalatest.FunSuiteLike.runTest$(FunSuiteLike.scala:178)
[info] at doobietest.MatViewSpec.org$scalatest$BeforeAndAfterEach$$super$runTest(MatViewSpec.scala:11)
[info] at org.scalatest.BeforeAndAfterEach.runTest(BeforeAndAfterEach.scala:221)
[info] at org.scalatest.BeforeAndAfterEach.runTest$(BeforeAndAfterEach.scala:214)
[info] at doobietest.MatViewSpec.runTest(MatViewSpec.scala:11)
[info] at org.scalatest.FunSuiteLike.$anonfun$runTests$1(FunSuiteLike.scala:229)
[info] at org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:396)
[info] at scala.collection.immutable.List.foreach(List.scala:389)
[info] at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:384)
[info] at org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:379)
[info] at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:461)
[info] at org.scalatest.FunSuiteLike.runTests(FunSuiteLike.scala:229)
[info] at org.scalatest.FunSuiteLike.runTests$(FunSuiteLike.scala:228)
[info] at org.scalatest.FunSuite.runTests(FunSuite.scala:1560)
[info] at org.scalatest.Suite.run(Suite.scala:1147)
[info] at org.scalatest.Suite.run$(Suite.scala:1129)
[info] at org.scalatest.FunSuite.org$scalatest$FunSuiteLike$$super$run(FunSuite.scala:1560)
[info] at org.scalatest.FunSuiteLike.$anonfun$run$1(FunSuiteLike.scala:233)
[info] at org.scalatest.SuperEngine.runImpl(Engine.scala:521)
[info] at org.scalatest.FunSuiteLike.run(FunSuiteLike.scala:233)
[info] at org.scalatest.FunSuiteLike.run$(FunSuiteLike.scala:232)
[info] at org.scalatest.FunSuite.run(FunSuite.scala:1560)
[info] at org.scalatest.tools.Framework.org$scalatest$tools$Framework$$runSuite(Framework.scala:314)
[info] at org.scalatest.tools.Framework$ScalaTestTask.execute(Framework.scala:507)
[info] at sbt.ForkMain$Run$2.call(ForkMain.java:296)
[info] at sbt.ForkMain$Run$2.call(ForkMain.java:286)
[info] at java.util.concurrent.FutureTask.run(FutureTask.java:266)
[info] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
[info] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
[info] at java.lang.Thread.run(Thread.java:748)
[info] ScalaTest
[info] Run completed in 3 seconds, 544 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 0, failed 1, canceled 0, ignored 0, pending 0
[info] *** 1 TEST FAILED ***
[error] Failed: Total 1, Failed 1, Errors 0, Passed 0
[error] Failed tests:
[error] doobietest.MatViewSpec
[error] (itemrecommender/it:testOnly) sbt.TestsFailedException: Tests unsuccessful
[error] Total time: 11 s, completed Feb 14, 2018 7:19:39 PM
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment