-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[tests] Add unit test for FeaturesTableRepositoryDAO
- Loading branch information
Ludovic Claude
committed
Dec 31, 2018
1 parent
d08ec99
commit 51a6650
Showing
8 changed files
with
358 additions
and
68 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
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
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
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,50 @@ | ||
/* | ||
* Copyright (C) 2017 LREN CHUV for Human Brain Project | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU Affero General Public License as | ||
* published by the Free Software Foundation, either version 3 of the | ||
* License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU Affero General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Affero General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
package ch.chuv.lren.woken.dao | ||
import java.sql.Connection | ||
|
||
import acolyte.jdbc.{ AbstractCompositeHandler, AcolyteDSL, ConnectionHandler } | ||
import cats.effect.{ ContextShift, IO, Resource } | ||
import cats.effect.internals.IOContextShift | ||
import doobie.util.ExecutionContexts | ||
import doobie.util.transactor.Transactor | ||
|
||
trait DAOTest[DAO <: Repository] { | ||
|
||
def withRepository(sqlHandler: AbstractCompositeHandler[_], | ||
mkDAO: Transactor[IO] => DAO)(testCode: DAO => Any): Unit = { | ||
|
||
val conn: Connection = AcolyteDSL.connection(sqlHandler) | ||
implicit val cs: ContextShift[IO] = IOContextShift.global | ||
|
||
// Resource yielding a Transactor[IO] wrapping the given `Connection` | ||
def transactor(c: Connection): Resource[IO, Transactor[IO]] = | ||
ExecutionContexts.cachedThreadPool[IO].flatMap { te => | ||
val t: Transactor[IO] = Transactor.fromConnection[IO](c, te) | ||
Resource.liftF(t.configure(_ => IO.pure(t))) | ||
} | ||
|
||
transactor(conn) | ||
.use { tr => | ||
val dao = mkDAO(tr) | ||
IO.delay(testCode(dao)) | ||
} | ||
.unsafeRunSync() | ||
} | ||
|
||
} |
147 changes: 147 additions & 0 deletions
147
src/test/scala/ch/chuv/lren/woken/dao/FeaturesTableRepositoryDAOTest.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,147 @@ | ||
/* | ||
* Copyright (C) 2017 LREN CHUV for Human Brain Project | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU Affero General Public License as | ||
* published by the Free Software Foundation, either version 3 of the | ||
* License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU Affero General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Affero General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
package ch.chuv.lren.woken.dao | ||
|
||
import acolyte.jdbc._ | ||
import acolyte.jdbc.RowLists.{ rowList1, rowList2 } | ||
import acolyte.jdbc.Implicits._ | ||
import cats.effect.IO | ||
import ch.chuv.lren.woken.core.model.database.TableColumn | ||
import ch.chuv.lren.woken.messages.datasets.DatasetId | ||
import ch.chuv.lren.woken.messages.query.filters._ | ||
import ch.chuv.lren.woken.messages.variables.SqlType | ||
import org.scalatest.{ Matchers, WordSpec } | ||
|
||
class FeaturesTableRepositoryDAOTest | ||
extends WordSpec | ||
with Matchers | ||
with DAOTest[FeaturesTableRepositoryDAO[IO]] | ||
with FeaturesTableTestSupport { | ||
|
||
val wokenRepository = new WokenInMemoryRepository[IO]() | ||
|
||
val sampleTableHandler: ScalaCompositeHandler = AcolyteDSL.handleStatement | ||
.withQueryDetection("^SELECT ") // regex test from beginning | ||
.withQueryHandler { e: QueryExecution => | ||
e.sql.trim match { | ||
|
||
case """SELECT count(*) FROM "Sample"""" => | ||
rowList1(classOf[Int]) :+ 99 | ||
|
||
case """SELECT count(*) FROM "Sample" WHERE "score_test1" >= 2 AND "cognitive_task2" < 9""" => | ||
rowList1(classOf[Int]) :+ 5 | ||
|
||
case """SELECT "college_math" , count(*) FROM "Sample" GROUP BY "college_math"""" => | ||
(rowList2(classOf[String], classOf[Int]) | ||
:+ ("0", 47) // tuple as row | ||
:+ ("1", 52)) | ||
|
||
case """SELECT "college_math" , count(*) FROM "Sample" WHERE "score_test1" >= 2 GROUP BY "college_math"""" => | ||
(rowList2(classOf[String], classOf[Int]) | ||
:+ ("0", 12) // tuple as row | ||
:+ ("1", 22)) | ||
|
||
case _ => throw new IllegalArgumentException(s"Unhandled $e") | ||
} | ||
} | ||
|
||
val cdeTableHandler: ScalaCompositeHandler = AcolyteDSL.handleStatement | ||
.withQueryDetection("^SELECT ") // regex test from beginning | ||
.withQueryHandler { e: QueryExecution => | ||
e.sql.trim match { | ||
|
||
case """SELECT count(*) FROM "cde_features_a" WHERE "dataset" = ?""" | ||
if e.parameters == List(DefinedParameter("datasetA", ParameterMetaData.Str)) => | ||
rowList1(classOf[Int]) :+ 5 | ||
|
||
case _ => throw new IllegalArgumentException(s"Unhandled $e") | ||
} | ||
} | ||
|
||
"FeaturesTableRepositoryDAO" should { | ||
|
||
"count all records in the table" in withRepository( | ||
sampleTableHandler, | ||
xa => new FeaturesTableRepositoryDAO[IO](xa, sampleTable, sampleHeaders, wokenRepository) | ||
) { dao => | ||
dao.count.unsafeRunSync() shouldBe 99 | ||
} | ||
|
||
"count all records matching a dataset for a table without a dataset column" in withRepository( | ||
sampleTableHandler, | ||
xa => new FeaturesTableRepositoryDAO[IO](xa, sampleTable, sampleHeaders, wokenRepository) | ||
) { dao => | ||
dao.count(DatasetId(sampleTable.table.name)).unsafeRunSync() shouldBe 99 | ||
dao.count(DatasetId("other")).unsafeRunSync() shouldBe 0 | ||
} | ||
|
||
"count all records matching a dataset for a table with a dataset column" in withRepository( | ||
cdeTableHandler, | ||
xa => new FeaturesTableRepositoryDAO[IO](xa, cdeTable, cdeHeaders, wokenRepository) | ||
) { dao => | ||
dao.count(DatasetId("datasetA")).unsafeRunSync() shouldBe 5 | ||
} | ||
|
||
"count all records matching a filter" in withRepository( | ||
sampleTableHandler, | ||
xa => new FeaturesTableRepositoryDAO[IO](xa, sampleTable, sampleHeaders, wokenRepository) | ||
) { dao => | ||
val filter = CompoundFilterRule( | ||
Condition.and, | ||
rules = List( | ||
SingleFilterRule("score_test1", | ||
"score_test1", | ||
"number", | ||
InputType.number, | ||
Operator.greaterOrEqual, | ||
List("2")), | ||
SingleFilterRule("cognitive_task2", | ||
"cognitive_task2", | ||
"number", | ||
InputType.number, | ||
Operator.less, | ||
List("9")) | ||
) | ||
) | ||
dao.count(None).unsafeRunSync() shouldBe 99 | ||
dao.count(Some(filter)).unsafeRunSync() shouldBe 5 | ||
} | ||
|
||
"count records grouped by a field" in withRepository( | ||
sampleTableHandler, | ||
xa => new FeaturesTableRepositoryDAO[IO](xa, sampleTable, sampleHeaders, wokenRepository) | ||
) { dao => | ||
dao.countGroupBy(TableColumn("college_math", SqlType.int), None).unsafeRunSync() shouldBe Map( | ||
"0" -> 47, | ||
"1" -> 52 | ||
) | ||
|
||
val filter = SingleFilterRule("score_test1", | ||
"score_test1", | ||
"number", | ||
InputType.number, | ||
Operator.greaterOrEqual, | ||
List("2")) | ||
|
||
dao | ||
.countGroupBy(TableColumn("college_math", SqlType.int), Some(filter)) | ||
.unsafeRunSync() shouldBe Map("0" -> 12, "1" -> 22) | ||
} | ||
|
||
} | ||
} |
73 changes: 73 additions & 0 deletions
73
src/test/scala/ch/chuv/lren/woken/dao/FeaturesTableTestSupport.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,73 @@ | ||
/* | ||
* Copyright (C) 2017 LREN CHUV for Human Brain Project | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU Affero General Public License as | ||
* published by the Free Software Foundation, either version 3 of the | ||
* License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU Affero General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Affero General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
package ch.chuv.lren.woken.dao | ||
import ch.chuv.lren.woken.core.model.database.{ FeaturesTableDescription, TableColumn, TableId } | ||
import ch.chuv.lren.woken.messages.variables.SqlType | ||
import spray.json.{ JsNumber, JsObject, JsString } | ||
|
||
trait FeaturesTableTestSupport { | ||
|
||
val database = "features_db" | ||
val sampleTable = FeaturesTableDescription(TableId(database, None, "Sample"), | ||
Nil, | ||
None, | ||
validateSchema = false, | ||
None, | ||
0.67) | ||
val sampleHeaders = List( | ||
TableColumn("ID", SqlType.int), | ||
TableColumn("stress_before_test1", SqlType.numeric), | ||
TableColumn("score_test1", SqlType.numeric), | ||
TableColumn("IQ", SqlType.numeric), | ||
TableColumn("cognitive_task2", SqlType.numeric), | ||
TableColumn("practice_task2", SqlType.numeric), | ||
TableColumn("response_time_task2", SqlType.numeric), | ||
TableColumn("college_math", SqlType.numeric), | ||
TableColumn("score_math_course1", SqlType.numeric), | ||
TableColumn("score_math_course2", SqlType.numeric) | ||
) | ||
|
||
val sampleData = List( | ||
JsObject("ID" -> JsNumber(1), | ||
"stress_before_test1" -> JsNumber(2.0), | ||
"score_test1" -> JsNumber(1.0)) | ||
) | ||
|
||
val cdeTable = FeaturesTableDescription( | ||
TableId(database, None, "cde_features_a"), | ||
List(TableColumn("subjectcode", SqlType.varchar)), | ||
Some(TableColumn("dataset", SqlType.varchar)), | ||
validateSchema = false, | ||
None, | ||
0.67 | ||
) | ||
val cdeHeaders = List( | ||
TableColumn("subjectcode", SqlType.varchar), | ||
TableColumn("apoe4", SqlType.int), | ||
TableColumn("lefthippocampus", SqlType.numeric), | ||
TableColumn("dataset", SqlType.varchar) | ||
) | ||
|
||
val cdeData = List( | ||
JsObject("subjectcode" -> JsString("p001"), | ||
"apoe4" -> JsNumber(2), | ||
"lefthippocampus" -> JsNumber(1.37), | ||
"dataset" -> JsString("desd-synthdata")) | ||
) | ||
|
||
} |
Oops, something went wrong.