Last active
February 14, 2018 18:20
-
-
Save FloWi/23d5603fd951e0df714ed6f545b3dd09 to your computer and use it in GitHub Desktop.
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
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) | |
} | |
} |
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
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