Created
August 2, 2019 06:45
-
-
Save symbiont-eric-torreborre/7a94f513347a05c38981b7214d7c973d to your computer and use it in GitHub Desktop.
api for global resources in specs2
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 describe a more or less ideal API for global resources management | |
// This trait allows to insert setup/teardown actions guaranteed to execute only once | |
// and making sure that the teardown action will always happen at the end of the | |
// specification execution | |
trait GlobalBeforeAfter extends SpecificationStructure with FragmentsFactory { | |
def globalBefore: Fragment | |
def globalAfter: Fragment | |
override def map(fs: =>Fragments): Fragments = super.map(fs).prepend( | |
Seq(globalBefore.memoize, fragmentFactory.markAs(AlwaysTag))). | |
andFinally(globalAfter.memoize) | |
} | |
// Then a user can declare its own trait for accessing a specific resource | |
trait MyDatabase extends GlobalBeforeAfter { | |
lazy val connection: IO[Connection] = newConnection | |
def globalBefore = | |
step(connection.unsafePerformIO) | |
def globalAfter = | |
step(connection.unsafePerformIO.kill) | |
} | |
// and use it in several specifications | |
class MySpec extends Specification with MyDatabase { def is = s2""" | |
the database can be used across several specifications and only created once $createOnce | |
the database will be shutdown safely when the last specification has finished executing $terminateDatabase | |
""" | |
def createOnce = todo | |
def terminateDatabase = todo | |
} | |
// The 2 major difficulties are: | |
// | |
// 1. the memoization of actions across several specification runs. | |
// | |
// If this is too hard to do we can require the user to define an object for creating a resource | |
// then it will be shared across specifications once started | |
object MyDatabase { | |
lazy val connection: Connection = newConnection.unsafePerformIO | |
} | |
// and we can require the teardown function to succeed even if the connection has already been closed | |
def globalAfter = | |
step(if (connection.isOpen) connection.kill) | |
// 2. sbt executes specifications one after the other (they are defined as "Tasks"). | |
// However the output of a task execution can be other tasks. So I think it is possible to use this | |
// mechanism to collect finalizers for each executed tasks and eventually execute all the finalizers |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment