From 8c5c12d95ffe52cfd576990c306d5b2e6fb606ec Mon Sep 17 00:00:00 2001
From: William Walker <wnwalker@ucsc.edu>
Date: Fri, 3 Jan 2025 21:41:47 -0800
Subject: [PATCH] chore: add test base, named test fields consistency

--Update env vault
--Create new abstract class which extends FunSpec() and allocates globally-used fields
--Remove coroutineDebugProbes since they break tests using Kotest (for now)
--Update duplicate course check test with new term code (Winter 2025)
---
 temerity/.env.vault                           |  4 +--
 .../its/temerity/test/DevDeviceApiTests.kt    | 16 ++++-----
 .../its/temerity/test/DevGroupApiTests.kt     | 13 +++----
 .../ucsc/its/temerity/test/DevUserApiTests.kt | 16 ++++-----
 .../ucsc/its/temerity/test/DevUtilityTests.kt | 17 +++------
 .../edu/ucsc/its/temerity/test/ModelTests.kt  | 13 ++++---
 .../ucsc/its/temerity/test/ProdReportTests.kt | 35 +++++++------------
 .../its/temerity/test/ProdUtilityTests.kt     | 14 +-------
 .../ucsc/its/temerity/test/TemerityDevTest.kt | 15 +++-----
 .../kotlin/edu/ucsc/its/temerity/test/Util.kt | 10 ++++++
 10 files changed, 61 insertions(+), 92 deletions(-)

diff --git a/temerity/.env.vault b/temerity/.env.vault
index 25e8b67..48fd5a7 100644
--- a/temerity/.env.vault
+++ b/temerity/.env.vault
@@ -4,8 +4,8 @@
 #/--------------------------------------------------/
 
 # development
-DOTENV_VAULT_DEVELOPMENT="DCHgKIC5D+Tef2A5UpGbSV6legsP/JCF7fUpqRdMwFsKbMst7VDmKDo4oLOvRCCgJl6ADvCm9oI2B79zntB1K5zRFo7TTbBtw9Vova+6X5BpoA7YYsf5N44aYKwsWqkRp6JD0p4VO0arpX1XWNjmK1LG2UPsfUU3gLu2I7plsYtSi4YRhNSh2gHccQCgC6FmQS9CG8KoQQFikW72DYmIMNALDq5xxKG2DgfRYTBER+qPwFAg7IQACIt/N4L9LEsrcnE1xFoPgwlLXUzLHlYpQpvfkg6V7brGobbcvUwf0+YsDHGFf48y9CGAOIlUYk9TgXyxi9T4Fa/bSwm+vLUDK7Mo26FI+8HIyaPgramA8X2+o6k73ULUfF8DAD2JiC5AWe42CSGaZAwCe0XILX/7iS4NTHnmX1Fx/zRAMxDZmPd0BTm9Mw9cXxtk1zeDAo37EUqKpztwMQ7PbMNjLeDzy/5DNAlO6Ke9u2RoUsphpolS6vm4Lnuheo9BlAk3N8inAzdPG8NMPhCfTmy1GmiseQtsUUdP4QtFRJtBSqJ2BBNTkD8bmwPWBdePM/w1jyLQhg4TRSpQtMydCJKt/WqqSzXq7JQJDz+9T3yH+snH8xiac/nQAvxocEw/CmA4kYsXsvYgFR7FgBTBW1ugcldfHx88eFZyPfJ/T9z0+IVovlTSUDOlWgFV8i4DbTUzYEu3mnoVTr2j98z0qzhpYu50MLl34ZtGVzQAuVWGmGvr+xueGQWhBzhKlPnNAmi5WEnnOY+ysnMaP+bIWHLbRmKyvWdRrxX8xySOEgsn7oH0mQZwWZZuYlHHGwT5CSSqe/LBNPTmSmOC6ZCj5Gf2q2dgCri1rzyyd2Ny7sI/22lB5WE1c7ltdxaVGtTHFt7wOrOrzAaklF4TlJD0gonje6ii+V7di/sn5uVbhpxvjbfnhWt82VYFK1F6Zr0xYwIjSehs7YUnlSLgsUzaWt6E/HbBB+3/M/0="
-DOTENV_VAULT_DEVELOPMENT_VERSION=20
+DOTENV_VAULT_DEVELOPMENT="ObnbpxIJgixKNbmk/oQmohcTxUbFL8RxERUxAo5WB4cCif7LZobiRAfZhutEygQosdaWcGkblPYs+IOZsBaX26BY9Y4gOCzuUQWRPR9l9a7ml6Qt2M0ilZUO2gOXjpJ1GHueYye4aOgi0HlFNlguxIKllCNncBebiQSdyxQcRVUvFncDmLrJavuse0LpCdfD1g31mOD2pzxwptUwPKYg7BG1dDdO5639pBAzrAwMho0yYYS2R6c578n1yepPgg5WV6nqWOqqHRc2/pcz2GwBZEwFeZwrciYKIAA28E5TBoM/ZcHHIIPdZn1M3ejFX8Sp5oSvT78YPcMCiX3Dpq+R9Gsl9FHVgJZAQAaMD4Dwrmu7tT7OWgF2v2PJBRnDRz1g7b1duC1eVKsa3SHTVr4bRHioLdRakzwkcSCxNndBPGndMXDeKTKJY8OHbgA1JyoTf21Wh5mhkQvhHrMr+1IzubSGoz5Z5zgjilNtBQOTSLZxG4YK/mA7v5o5x9RJ8ce3N//OZgTHpDC/2n8QmhQpZsqr9A1rB4o87WCGoklZfQTturDayqoXWNIHmlJ+WDdtAyDsLYu9eQdHOlh4GZY94kNRMtwVicbTLevr7pvc5aY/PIwu8kgpAD4UL96b75J3UZ0u4kzaczoS837bCnFlxgPTkFs0G2oZx975pNJSuwyyvRk5/ADskKZgW5gxF0kAcO7h/+GKPLhZOXm50peNaQbJjabT/e7x3jR7rrCVFwEQloovWL7/lHklze9kntrIuBB704by74KfqYCV/RIVukSkazrwU6KY3EyswU1N8yj8g3wzd5V7LUnaFX1pqijtc7mUr30piM/DHALTJfAfYa2KQwzuIJ1egJhCT5kWSv7wKyMtGvNcZrNIYS8pkk9pqsW/YJ2JDwqJFh9/f32nk0Oj4LQk19j0DNdmu4QRdmeRrVx/pEPl24s8GPzQGoUly6N14psmIH0luV7yY+QU0NAU0ho="
+DOTENV_VAULT_DEVELOPMENT_VERSION=21
 
 # ci
 DOTENV_VAULT_CI="n69uhs4m6qCfBKFNpDoqnpPfqeXrU+T3VIO+eseGVKWbRjZhRxx3VqAqq1P5Pml/YNJSR3t7N48cOQEhQdEvgwgIceG6DtJClkHZy712jhivwt6CVF7Hi0znBM9G0mub/guVwTUngFBRsQKw3XpDnxrzfo/FUPP09Zhy3D604wDnKuk/M6cUgT4o3jucOXmsjnwZTm/UUz+65eRSB0L5O8Gy7tB1e30eH5WUmx+hnG85v9+QENjt1inU9bZuefwnf7XzSaPKisVZVm4AYxXWnGIVP84Wy2O2h5nytLPdw2Z72mwaGSTRp0miUtUynTtFsm/SeoIOAgbixm7ScF4o/juwfq6IhVUBDfZStjXMx/150U2QZVbseVHKWrIdpPy9bZ7gO2ufMDps+daXWsJsHRqe11UTPhyZ8jA5V0oxDHe1y1cf0Dr9ZUr0g4E="
diff --git a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevDeviceApiTests.kt b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevDeviceApiTests.kt
index 058672e..efec752 100644
--- a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevDeviceApiTests.kt
+++ b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevDeviceApiTests.kt
@@ -18,27 +18,23 @@
 package edu.ucsc.its.temerity.test
 
 import edu.ucsc.its.temerity.core.Temerity
-import io.kotest.core.spec.style.FunSpec
 import kotlinx.coroutines.runBlocking
 
-class DevDeviceApiTests :
-  FunSpec({
-    val dotenv = dotenvVaultJvm()
-
-    lateinit var temerityTest: Temerity
-
+private class DevDeviceApiTests : TemerityFunSpec() {
+  init {
     beforeTest {
-      temerityTest = Temerity {
+      testTemerity = Temerity {
         configureDevEnvironment(dotenv)
       }
     }
 
     test("4.2.1 - PlatformClient can fetch a list of devices") {
       runBlocking {
-        val returnedDevices = temerityTest.getDevices()
+        val returnedDevices = testTemerity.getDevices()
         println("Returned devices:")
         returnedDevices.forEach { println(it) }
         assert(returnedDevices.isNotEmpty())
       }
     }
-  })
+  }
+}
diff --git a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevGroupApiTests.kt b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevGroupApiTests.kt
index 3658f24..521acc2 100644
--- a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevGroupApiTests.kt
+++ b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevGroupApiTests.kt
@@ -18,16 +18,10 @@
 package edu.ucsc.its.temerity.test
 
 import edu.ucsc.its.temerity.core.Temerity
-import io.kotest.core.spec.style.FunSpec
 import kotlinx.coroutines.runBlocking
 
-class DevGroupApiTests :
-  FunSpec({
-
-    val dotenv = dotenvVaultJvm()
-
-    lateinit var testTemerity: Temerity
-
+private class DevGroupApiTests : TemerityFunSpec() {
+  init {
     beforeTest {
       testTemerity = Temerity {
         configureDevEnvironment(dotenv)
@@ -42,4 +36,5 @@ class DevGroupApiTests :
         assert(returnedGroups.isNotEmpty())
       }
     }
-  })
+  }
+}
diff --git a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevUserApiTests.kt b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevUserApiTests.kt
index 57ac043..43885a0 100644
--- a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevUserApiTests.kt
+++ b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevUserApiTests.kt
@@ -21,21 +21,18 @@ import co.touchlab.kermit.Logger
 import com.skydoves.sandwich.StatusCode
 import com.skydoves.sandwich.ktor.getStatusCode
 import edu.ucsc.its.temerity.core.Temerity
-import edu.ucsc.its.temerity.core.Temerity.Companion.createLogger
 import edu.ucsc.its.temerity.model.NewUser
 import edu.ucsc.its.temerity.model.UserUpdate
-import io.kotest.core.spec.style.FunSpec
+import io.kotest.common.ExperimentalKotest
 import io.kotest.matchers.shouldBe
 import io.ktor.http.HttpStatusCode
 import kotlinx.coroutines.runBlocking
 
-class DevUserApiTests :
-  FunSpec({
+private class DevUserApiTests : TemerityFunSpec() {
+  init {
+    @OptIn(ExperimentalKotest::class)
+    blockingTest = true
 
-    val dotenv = dotenvVaultJvm()
-    val kermit = createLogger(tag = "DevUserApiTests")
-
-    lateinit var testTemerity: Temerity
     beforeTest {
       testTemerity = Temerity {
         configureDevEnvironment(dotenv)
@@ -141,4 +138,5 @@ class DevUserApiTests :
         }
       }
     }
-  })
+  }
+}
diff --git a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevUtilityTests.kt b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevUtilityTests.kt
index 19a62a3..aa3e10b 100644
--- a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevUtilityTests.kt
+++ b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/DevUtilityTests.kt
@@ -18,25 +18,16 @@
 package edu.ucsc.its.temerity.test
 
 import edu.ucsc.its.temerity.core.Temerity
-import edu.ucsc.its.temerity.core.Temerity.Companion.createLogger
-import io.kotest.core.spec.style.FunSpec
+import io.kotest.common.ExperimentalKotest
 import io.kotest.engine.runBlocking
-import org.koin.test.KoinTest
 import kotlin.time.Duration.Companion.hours
 import kotlin.time.Duration.Companion.minutes
 
-class DevUtilityTests :
-  FunSpec(),
-  KoinTest {
-
-  private val kermit = createLogger("DevUtilityTests")
+private class DevUtilityTests : TemerityFunSpec() {
 
   init {
-    coroutineDebugProbes = true
-
-    val dotenv = dotenvVaultJvm()
-
-    lateinit var testTemerity: Temerity
+    @OptIn(ExperimentalKotest::class)
+    blockingTest = true
 
     beforeTest {
       testTemerity = Temerity {
diff --git a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ModelTests.kt b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ModelTests.kt
index 998583d..cec8e21 100644
--- a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ModelTests.kt
+++ b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ModelTests.kt
@@ -18,14 +18,19 @@
 package edu.ucsc.its.temerity.test
 
 import edu.ucsc.its.temerity.model.EventType
-import io.kotest.core.spec.style.FunSpec
+import io.kotest.common.ExperimentalKotest
+
+private class ModelTests : TemerityFunSpec() {
+
+  init {
+    @OptIn(ExperimentalKotest::class)
+    blockingTest = true
 
-class ModelTests :
-  FunSpec({
     test("Return enum AuditLog EventTypes in alphabetical order") {
       val sortedEventTypes = EventType.entries.sortedBy { it.value }
       sortedEventTypes.forEach {
         println(it.value)
       }
     }
-  })
+  }
+}
diff --git a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ProdReportTests.kt b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ProdReportTests.kt
index 5ce6590..9589c8b 100644
--- a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ProdReportTests.kt
+++ b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ProdReportTests.kt
@@ -19,8 +19,6 @@ package edu.ucsc.its.temerity.test
 
 import edu.ucsc.its.temerity.AuditLogSortOrder.NEW_FIRST
 import edu.ucsc.its.temerity.core.Temerity
-import edu.ucsc.its.temerity.core.Temerity.Companion.createLogger
-import edu.ucsc.its.temerity.core.Temerity.Companion.currentDate
 import edu.ucsc.its.temerity.model.EventType.AUTOMATED_SESSION_FAILED_TO_START
 import edu.ucsc.its.temerity.model.EventType.AUTOMATED_SESSION_MONITOR
 import edu.ucsc.its.temerity.model.EventType.CAPTURE_ERROR
@@ -32,7 +30,8 @@ import edu.ucsc.its.temerity.model.EventType.HDCP_SIGNAL_DETECTED
 import edu.ucsc.its.temerity.model.EventType.HUB_CAPTURE_PROBLEM
 import edu.ucsc.its.temerity.model.EventType.NEW_LOG_IN
 import edu.ucsc.its.temerity.model.EventType.RECORDING_ERROR
-import io.kotest.core.spec.style.FunSpec
+import edu.ucsc.its.temerity.util.currentDate
+import io.kotest.common.ExperimentalKotest
 import io.kotest.matchers.file.shouldNotBeEmpty
 import kotlinx.coroutines.runBlocking
 import kotlinx.datetime.Clock
@@ -42,26 +41,18 @@ import kotlinx.datetime.minus
 import kotlinx.datetime.todayIn
 import org.jetbrains.kotlinx.dataframe.api.toDataFrame
 import org.jetbrains.kotlinx.dataframe.io.writeCSV
-import org.koin.test.KoinTest
 import java.io.File
 import kotlin.time.Duration.Companion.minutes
 import kotlin.uuid.ExperimentalUuidApi
 import kotlin.uuid.Uuid
-import co.touchlab.kermit.Logger as KermitLogger
 
 @OptIn(ExperimentalUuidApi::class)
-class ProdReportTests :
-  FunSpec(),
-  KoinTest {
-
-  private val kermit: KermitLogger = createLogger(tag = "TemerityDevTest")
+private class ProdReportTests : TemerityFunSpec() {
 
   init {
-    coroutineDebugProbes = true
-
-    val dotenv = dotenvVaultJvm()
+    @OptIn(ExperimentalKotest::class)
+    blockingTest = true
 
-    lateinit var testTemerity: Temerity
     val today = currentDate()
 
     beforeTest {
@@ -176,23 +167,23 @@ class ProdReportTests :
       }
     }
 
-    // "Mislinked" YuJa course group report
-    // Generate Report listing all groups matching specific sis id that have the wrong term code, or are duplicates
-    test("PlatformClient can fetch a list of groups with specific SIS ID by term and verifying term code matches") {
+    // "Mislinked" YuJa course report
+    // Generate Report listing all courses matching specific sis id that have the wrong term code, or are duplicates
+    test("PlatformClient can fetch a list of courses with specific SIS ID by term and verify that the term code matches the correct one for the quarter") {
       runBlocking {
         val fullCoursesList = testTemerity.getCourses()
         val invalidGroupTerm = fullCoursesList.filter {
-          it.sisId.startsWith("2248")
+          it.sisId.startsWith("2250")
         }.filter {
-          it.courseTerm != "2024 Fall Quarter"
+          it.courseTerm != "2025 Winter Quarter"
         }
         val nonMatchingSisId = fullCoursesList.filter {
-          it.courseTerm == "2024 Fall Quarter"
+          it.courseTerm == "2025 Winter Quarter"
         }.filter {
-          !it.sisId.startsWith("2248")
+          !it.sisId.startsWith("2250")
         }
         val duplicateSisId = fullCoursesList.filter {
-          it.sisId.startsWith("2248")
+          it.sisId.startsWith("2250")
         }.groupBy { it.sisId }.filter { it.value.size > 1 }.values.flatten()
         val problemCourses = invalidGroupTerm + nonMatchingSisId + duplicateSisId
         println("Total returned groups count: ${problemCourses.size}")
diff --git a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ProdUtilityTests.kt b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ProdUtilityTests.kt
index 6e43ac6..632ec39 100644
--- a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ProdUtilityTests.kt
+++ b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/ProdUtilityTests.kt
@@ -18,29 +18,17 @@
 package edu.ucsc.its.temerity.test
 
 import edu.ucsc.its.temerity.core.Temerity
-import edu.ucsc.its.temerity.core.Temerity.Companion.createLogger
 import io.kotest.common.ExperimentalKotest
-import io.kotest.core.spec.style.FunSpec
 import io.kotest.engine.runBlocking
-import org.koin.test.KoinTest
 import kotlin.time.Duration.Companion.hours
 import kotlin.time.Duration.Companion.minutes
 
-class ProdUtilityTests :
-  FunSpec(),
-  KoinTest {
-
-  private val kermit = createLogger("ProdUtilityTests")
+private class ProdUtilityTests : TemerityFunSpec() {
 
   init {
-    coroutineDebugProbes = true
     @OptIn(ExperimentalKotest::class)
     blockingTest = true
 
-    val dotenv = dotenvVaultJvm()
-
-    lateinit var testTemerity: Temerity
-
     beforeTest {
       testTemerity = Temerity {
         configureProdEnvironment(dotenv)
diff --git a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/TemerityDevTest.kt b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/TemerityDevTest.kt
index 51fd825..dd216fc 100644
--- a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/TemerityDevTest.kt
+++ b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/TemerityDevTest.kt
@@ -22,12 +22,12 @@ import com.skydoves.sandwich.StatusCode
 import com.skydoves.sandwich.ktor.getStatusCode
 import edu.ucsc.its.temerity.AuditLogSortOrder.NEW_FIRST
 import edu.ucsc.its.temerity.core.Temerity
-import edu.ucsc.its.temerity.core.Temerity.Companion.currentDate
 import edu.ucsc.its.temerity.model.EventType.NEW_LOG_IN
 import edu.ucsc.its.temerity.model.NewUser
+import edu.ucsc.its.temerity.util.currentDate
 import io.github.z4kn4fein.semver.Version
 import io.github.z4kn4fein.semver.toVersion
-import io.kotest.core.spec.style.FunSpec
+import io.kotest.common.ExperimentalKotest
 import io.kotest.matchers.file.shouldNotBeEmpty
 import io.kotest.matchers.shouldBe
 import kotlinx.coroutines.runBlocking
@@ -42,20 +42,15 @@ import kotlin.uuid.ExperimentalUuidApi
 import kotlin.uuid.Uuid
 
 @OptIn(ExperimentalUuidApi::class)
-class TemerityDevTest : FunSpec() {
-
-  private lateinit var kermit: Logger
-
+private class TemerityDevTest : TemerityFunSpec() {
   init {
-    val dotenv = dotenvVaultJvm()
-
-    lateinit var testTemerity: Temerity
+    @OptIn(ExperimentalKotest::class)
+    blockingTest = true
 
     beforeTest {
       testTemerity = Temerity {
         configureDevEnvironment(dotenv)
       }
-      kermit = Temerity.createLogger("TemerityDevTest")
     }
 
     test("Temerity client returns a correctly-formatted version String") {
diff --git a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/Util.kt b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/Util.kt
index 1f0e873..299c20b 100644
--- a/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/Util.kt
+++ b/temerity/src/jvmTest/kotlin/edu/ucsc/its/temerity/test/Util.kt
@@ -18,10 +18,13 @@
 package edu.ucsc.its.temerity.test
 
 import edu.ucsc.its.temerity.TemClientConfig
+import edu.ucsc.its.temerity.core.Temerity
+import edu.ucsc.its.temerity.core.Temerity.Companion.createLogger
 import io.github.cdimascio.dotenv.Configuration
 import io.github.cdimascio.dotenv.Dotenv
 import io.github.cdimascio.dotenv.dotenv
 import io.kotest.core.extensions.TestCaseExtension
+import io.kotest.core.spec.style.FunSpec
 import io.kotest.core.test.TestCase
 import io.kotest.core.test.TestResult
 import io.kotest.core.test.TestType
@@ -31,6 +34,7 @@ import org.koin.core.context.stopKoin
 import org.koin.core.module.Module
 import org.koin.test.mock.MockProvider
 import org.koin.test.mock.Provider
+import co.touchlab.kermit.Logger as KermitLogger
 
 // Utility function from: https://github.com/alvr/katana/blob/d10a53486b95bbc2cfaa0fed636b913957334366/core/tests/src/commonMain/kotlin/dev/alvr/katana/core/tests/KoinExtension.kt
 // Originally based on kotest koin extension: https://github.com/kotest/kotest-extensions-koin/blob/30bc2867dd3adfe4e3dc164f97031146563d4435/src/commonMain/kotlin/io.kotest.koin/KoinExtension.kt
@@ -94,3 +98,9 @@ fun dotenvVaultJvm(block: (Configuration.() -> Unit)? = null): Dotenv = when (bl
     block()
   }
 }
+
+internal abstract class TemerityFunSpec : FunSpec() {
+  internal val dotenv: Dotenv = dotenvVaultJvm()
+  internal val kermit: KermitLogger = createLogger()
+  internal lateinit var testTemerity: Temerity
+}
-- 
GitLab