1 /*
2  *  Make.org Core API
3  *  Copyright (C) 2018 Make.org
4  *
5  * This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU Affero General Public License as
7  *  published by the Free Software Foundation, either version 3 of the
8  *  License, or (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU Affero General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Affero General Public License
16  *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
17  *
18  */
19 
20 package org.make.api
21 
22 import com.github.t3hnar.bcrypt._
23 import javax.sql.DataSource
24 import org.apache.commons.dbcp2.BasicDataSource
25 import org.flywaydb.core.Flyway
26 import org.make.api.docker.DockerCockroachService
27 import org.make.api.extensions.MakeDBExecutionContextComponent
28 import scalikejdbc.{ConnectionPool, DataSourceConnectionPool, GlobalSettings, LoggingSQLAndTimeSettings}
29 
30 import scala.annotation.tailrec
31 import scala.jdk.CollectionConverters._
32 import scala.concurrent.ExecutionContext
33 import scala.util.{Failure, Success, Try}
34 import scala.concurrent.duration.DurationInt
35 
36 trait DatabaseTest extends MakeUnitTest with DockerCockroachService with MakeDBExecutionContextComponent {
37 
38   override val readExecutionContext: ExecutionContext = ExecutionContext.Implicits.global
39   override val writeExecutionContext: ExecutionContext = ExecutionContext.Implicits.global
40 
41   protected def databaseName: String = "makeapitest"
42 
43   protected def defaultClientId: String = "clientId"
44   protected def defaultClientSecret: String = "clientSecret"
45   protected def defaultBackofficeClientId: String = "backofficeClientId"
46   protected def defaultBackofficeClientSecret: String = "backofficeClientSecret"
47   protected def adminFirstName: String = "admin"
48   protected def adminEmail: String = "admin@example.com"
49   protected def adminPassword: String = "passpass".boundedBcrypt
50 
51   @SuppressWarnings(Array("org.wartremover.warts.ThreadSleep"))
52   override def beforeAll(): Unit = {
53     super.beforeAll()
54 
55     GlobalSettings.loggingSQLErrors = true
56     GlobalSettings.loggingSQLAndTime = LoggingSQLAndTimeSettings(
57       enabled = true,
58       warningEnabled = false,
59       printUnprocessedStackTrace = true,
60       logLevel = "info"
61     )
62 
63     val dataSource: DataSource = createDataSource
64 
65     logger.debug(s"Creating database with name: $databaseName")
66 
67     val connection = dataSource.getConnection
68     connection.prepareStatement(s"CREATE DATABASE $databaseName").execute()
69     connection.close()
70 
71     ConnectionPool.add("WRITE", new DataSourceConnectionPool(dataSource))
72     ConnectionPool.add("READ", new DataSourceConnectionPool(dataSource))
73 
74     Thread.sleep(1.second.toMillis)
75 
76     val flyway: Flyway = Flyway
77       .configure()
78       .dataSource(dataSource)
79       .initSql("SET autocommit_before_ddl = off")
80       .baselineOnMigrate(true)
81       .locations("classpath:db/migration", "classpath:org/make/api/migrations/db")
82       .placeholders(
83         Map(
84           "dbname" -> databaseName,
85           "clientId" -> defaultClientId,
86           "clientSecret" -> defaultClientSecret,
87           "backofficeClientId" -> defaultBackofficeClientId,
88           "backofficeClientSecret" -> defaultBackofficeClientSecret,
89           "adminEmail" -> adminEmail,
90           "adminFirstName" -> adminFirstName,
91           "adminEncryptedPassword" -> adminPassword.boundedBcrypt
92         ).asJava
93       )
94       .load()
95 
96     @SuppressWarnings(Array("org.wartremover.warts.Throw"))
97     @tailrec
98     def migrateFlyway(nRetries: Int = 3): Unit =
99       Try(flyway.migrate()) match {
100         case Success(_)                  =>
101         case Failure(e) if nRetries <= 0 => throw e
102         case _ =>
103           flyway.repair()
104           migrateFlyway(nRetries - 1)
105       }
106 
107     migrateFlyway()
108 
109     Try(flyway.validate()) match {
110       case Success(_) => logger.info("Database schema created")
111       case Failure(e) => logger.warn("Cannot migrate database:", e)
112     }
113 
114   }
115 
116   private def createDataSource: DataSource = {
117     val writeDataSource = new BasicDataSource()
118     writeDataSource.setDriverClassName("org.postgresql.Driver")
119     writeDataSource.setUrl(s"jdbc:postgresql://localhost:$cockroachExposedPort/$databaseName")
120     writeDataSource.setUsername("root")
121     writeDataSource
122   }
123 }
Line Stmt Id Pos Tree Symbol Tests Code
38 22156 1493 - 1526 Select scala.concurrent.ExecutionContext.Implicits.global org.make.api.databasetest scala.concurrent.ExecutionContext.Implicits.global
39 22068 1584 - 1617 Select scala.concurrent.ExecutionContext.Implicits.global org.make.api.databasetest scala.concurrent.ExecutionContext.Implicits.global
41 22222 1658 - 1671 Literal <nosymbol> org.make.api.databasetest "makeapitest"
43 22128 1715 - 1725 Literal <nosymbol> org.make.api.databasetest "clientId"
44 22071 1772 - 1786 Literal <nosymbol> org.make.api.databasetest "clientSecret"
45 22238 1839 - 1859 Literal <nosymbol> org.make.api.databasetest "backofficeClientId"
46 22140 1916 - 1940 Literal <nosymbol> org.make.api.databasetest "backofficeClientSecret"
47 22047 1982 - 1989 Literal <nosymbol> org.make.api.databasetest "admin"
48 22218 2027 - 2046 Literal <nosymbol> org.make.api.databasetest "admin@example.com"
49 22058 2087 - 2111 Select com.github.t3hnar.bcrypt.BCryptStrOps.boundedBcrypt org.make.api.databasetest com.github.t3hnar.bcrypt.`package`.BCryptStrOps("passpass").boundedBcrypt
49 22151 2087 - 2097 Literal <nosymbol> org.make.api.databasetest "passpass"
53 22224 2218 - 2235 Apply com.whisk.docker.scalatest.DockerTestKit.beforeAll org.make.api.databasetest DatabaseTest.super.beforeAll()
55 22129 2241 - 2279 Apply scalikejdbc.GlobalSettings.loggingSQLErrors_= org.make.api.databasetest scalikejdbc.GlobalSettings.loggingSQLErrors_=(true)
56 22217 2319 - 2319 Select scalikejdbc.LoggingSQLAndTimeSettings.apply$default$2 org.make.api.databasetest scalikejdbc.LoggingSQLAndTimeSettings.apply$default$2
56 22067 2319 - 2319 Select scalikejdbc.LoggingSQLAndTimeSettings.apply$default$7 org.make.api.databasetest scalikejdbc.LoggingSQLAndTimeSettings.apply$default$7
56 22147 2284 - 2468 Apply scalikejdbc.GlobalSettings.loggingSQLAndTime_= org.make.api.databasetest scalikejdbc.GlobalSettings.loggingSQLAndTime_=({ <artifact> val x$1: Boolean(true) = true; <artifact> val x$2: Boolean(false) = false; <artifact> val x$3: Boolean(true) = true; <artifact> val x$4: String("info") = "info"; <artifact> val x$5: Boolean = scalikejdbc.LoggingSQLAndTimeSettings.apply$default$2; <artifact> val x$6: Int = scalikejdbc.LoggingSQLAndTimeSettings.apply$default$4; <artifact> val x$7: Long = scalikejdbc.LoggingSQLAndTimeSettings.apply$default$7; <artifact> val x$8: String = scalikejdbc.LoggingSQLAndTimeSettings.apply$default$8; <artifact> val x$9: Option[Int] @scala.reflect.internal.annotations.uncheckedBounds = scalikejdbc.LoggingSQLAndTimeSettings.apply$default$9; <artifact> val x$10: Option[Int] @scala.reflect.internal.annotations.uncheckedBounds = scalikejdbc.LoggingSQLAndTimeSettings.apply$default$10; scalikejdbc.LoggingSQLAndTimeSettings.apply(true, x$5, true, x$6, "info", false, x$7, x$8, x$9, x$10) })
56 22024 2319 - 2319 Select scalikejdbc.LoggingSQLAndTimeSettings.apply$default$10 org.make.api.databasetest scalikejdbc.LoggingSQLAndTimeSettings.apply$default$10
56 22221 2319 - 2319 Select scalikejdbc.LoggingSQLAndTimeSettings.apply$default$8 org.make.api.databasetest scalikejdbc.LoggingSQLAndTimeSettings.apply$default$8
56 22161 2319 - 2319 Select scalikejdbc.LoggingSQLAndTimeSettings.apply$default$4 org.make.api.databasetest scalikejdbc.LoggingSQLAndTimeSettings.apply$default$4
56 22236 2319 - 2468 Apply scalikejdbc.LoggingSQLAndTimeSettings.apply org.make.api.databasetest scalikejdbc.LoggingSQLAndTimeSettings.apply(true, x$5, true, x$6, "info", false, x$7, x$8, x$9, x$10)
56 22133 2319 - 2319 Select scalikejdbc.LoggingSQLAndTimeSettings.apply$default$9 org.make.api.databasetest scalikejdbc.LoggingSQLAndTimeSettings.apply$default$9
57 22078 2362 - 2366 Literal <nosymbol> org.make.api.databasetest true
58 22232 2391 - 2396 Literal <nosymbol> org.make.api.databasetest false
59 22138 2433 - 2437 Literal <nosymbol> org.make.api.databasetest true
60 22049 2456 - 2462 Literal <nosymbol> org.make.api.databasetest "info"
63 22050 2503 - 2519 Select org.make.api.DatabaseTest.createDataSource org.make.api.databasetest DatabaseTest.this.createDataSource
65 22212 2525 - 2584 Apply grizzled.slf4j.Logger.debug org.make.api.databasetest DatabaseTest.this.logger.debug(("Creating database with name: ".+(DatabaseTest.this.databaseName): String))
67 22162 2607 - 2631 Apply javax.sql.DataSource.getConnection org.make.api.databasetest dataSource.getConnection()
68 22061 2636 - 2707 Apply java.sql.PreparedStatement.execute org.make.api.databasetest connection.prepareStatement(("CREATE DATABASE ".+(DatabaseTest.this.databaseName): String)).execute()
69 22228 2712 - 2730 Apply java.sql.Connection.close org.make.api.databasetest connection.close()
71 22148 2764 - 2804 Apply scalikejdbc.DataSourceConnectionPool.<init> org.make.api.databasetest new scalikejdbc.DataSourceConnectionPool(dataSource, scalikejdbc.this.DataSourceConnectionPool.<init>$default$2, scalikejdbc.this.DataSourceConnectionPool.<init>$default$3)
71 22046 2736 - 2805 Apply scalikejdbc.ConnectionPool.add org.make.api.databasetest scalikejdbc.ConnectionPool.add("WRITE", new scalikejdbc.DataSourceConnectionPool(dataSource, scalikejdbc.this.DataSourceConnectionPool.<init>$default$2, scalikejdbc.this.DataSourceConnectionPool.<init>$default$3))
71 22237 2764 - 2764 Select scalikejdbc.DataSourceConnectionPool.<init>$default$3 org.make.api.databasetest scalikejdbc.this.DataSourceConnectionPool.<init>$default$3
71 22134 2755 - 2762 Literal <nosymbol> org.make.api.databasetest "WRITE"
71 22038 2764 - 2764 Select scalikejdbc.DataSourceConnectionPool.<init>$default$2 org.make.api.databasetest scalikejdbc.this.DataSourceConnectionPool.<init>$default$2
72 22154 2837 - 2837 Select scalikejdbc.DataSourceConnectionPool.<init>$default$2 org.make.api.databasetest scalikejdbc.this.DataSourceConnectionPool.<init>$default$2
72 22213 2829 - 2835 Literal <nosymbol> org.make.api.databasetest "READ"
72 22062 2837 - 2837 Select scalikejdbc.DataSourceConnectionPool.<init>$default$3 org.make.api.databasetest scalikejdbc.this.DataSourceConnectionPool.<init>$default$3
72 22125 2810 - 2878 Apply scalikejdbc.ConnectionPool.add org.make.api.databasetest scalikejdbc.ConnectionPool.add("READ", new scalikejdbc.DataSourceConnectionPool(dataSource, scalikejdbc.this.DataSourceConnectionPool.<init>$default$2, scalikejdbc.this.DataSourceConnectionPool.<init>$default$3))
72 22229 2837 - 2877 Apply scalikejdbc.DataSourceConnectionPool.<init> org.make.api.databasetest new scalikejdbc.DataSourceConnectionPool(dataSource, scalikejdbc.this.DataSourceConnectionPool.<init>$default$2, scalikejdbc.this.DataSourceConnectionPool.<init>$default$3)
74 22145 2884 - 2915 Apply java.lang.Thread.sleep org.make.api.databasetest java.lang.Thread.sleep(scala.concurrent.duration.`package`.DurationInt(1).second.toMillis)
74 22234 2897 - 2914 Select scala.concurrent.duration.FiniteDuration.toMillis org.make.api.databasetest scala.concurrent.duration.`package`.DurationInt(1).second.toMillis
74 22039 2897 - 2898 Literal <nosymbol> org.make.api.databasetest 1
94 22048 2942 - 3640 Apply org.flywaydb.core.api.configuration.FluentConfiguration.load org.make.api.databasetest org.flywaydb.core.Flyway.configure().dataSource(dataSource).initSql("SET autocommit_before_ddl = off").baselineOnMigrate(true).locations("classpath:db/migration", "classpath:org/make/api/migrations/db").placeholders(scala.jdk.CollectionConverters.MapHasAsJava[String, String](scala.Predef.Map.apply[String, String](scala.Predef.ArrowAssoc[String]("dbname").->[String](DatabaseTest.this.databaseName), scala.Predef.ArrowAssoc[String]("clientId").->[String](DatabaseTest.this.defaultClientId), scala.Predef.ArrowAssoc[String]("clientSecret").->[String](DatabaseTest.this.defaultClientSecret), scala.Predef.ArrowAssoc[String]("backofficeClientId").->[String](DatabaseTest.this.defaultBackofficeClientId), scala.Predef.ArrowAssoc[String]("backofficeClientSecret").->[String](DatabaseTest.this.defaultBackofficeClientSecret), scala.Predef.ArrowAssoc[String]("adminEmail").->[String](DatabaseTest.this.adminEmail), scala.Predef.ArrowAssoc[String]("adminFirstName").->[String](DatabaseTest.this.adminFirstName), scala.Predef.ArrowAssoc[String]("adminEncryptedPassword").->[String](com.github.t3hnar.bcrypt.`package`.BCryptStrOps(DatabaseTest.this.adminPassword).boundedBcrypt))).asJava).load()
99 22103 3770 - 3791 Apply scala.util.Try.apply org.make.api.databasetest scala.util.Try.apply[org.flywaydb.core.api.output.MigrateResult](flyway.migrate())
99 22203 3774 - 3790 Apply org.flywaydb.core.Flyway.migrate org.make.api.databasetest flyway.migrate()
100 22063 3841 - 3843 Literal <nosymbol> org.make.api.databasetest ()
101 22219 3871 - 3884 Apply scala.Int.<= nRetries.<=(0)
101 22126 3888 - 3895 Throw <nosymbol> throw e
103 22035 3924 - 3939 Apply org.flywaydb.core.Flyway.repair flyway.repair()
104 22235 3964 - 3976 Apply scala.Int.- nRetries.-(1)
104 22144 3950 - 3977 Apply org.make.api.DatabaseTest.migrateFlyway migrateFlyway(nRetries.-(1))
107 22043 3991 - 4006 Apply org.make.api.DatabaseTest.migrateFlyway org.make.api.databasetest migrateFlyway(migrateFlyway$default$1)
109 22204 4016 - 4033 Apply org.flywaydb.core.Flyway.validate org.make.api.databasetest flyway.validate()
109 22116 4012 - 4034 Apply scala.util.Try.apply org.make.api.databasetest scala.util.Try.apply[Unit](flyway.validate())
110 22060 4068 - 4106 Apply grizzled.slf4j.Logger.info org.make.api.databasetest DatabaseTest.this.logger.info("Database schema created")
111 22220 4132 - 4174 Apply grizzled.slf4j.Logger.warn DatabaseTest.this.logger.warn("Cannot migrate database:", e)
117 22123 4260 - 4281 Apply org.apache.commons.dbcp2.BasicDataSource.<init> org.make.api.databasetest new org.apache.commons.dbcp2.BasicDataSource()
118 22036 4286 - 4345 Apply org.apache.commons.dbcp2.BasicDataSource.setDriverClassName org.make.api.databasetest writeDataSource.setDriverClassName("org.postgresql.Driver")
119 22180 4350 - 4440 Apply org.apache.commons.dbcp2.BasicDataSource.setUrl org.make.api.databasetest writeDataSource.setUrl(("jdbc:postgresql://localhost:".+(DatabaseTest.this.cockroachExposedPort).+("/").+(DatabaseTest.this.databaseName): String))
120 22150 4445 - 4480 Apply org.apache.commons.dbcp2.BasicDataSource.setUsername org.make.api.databasetest writeDataSource.setUsername("root")