<@UFGCACPE0> There's no cleanUp block for shared {...
# opensavvy
d
@CLOVIS There's no cleanUp block for shared { } (like for taking down the db after the whole test class's run)?
c
Yes,
cleanUp
is test-specific, and shared values aren't. Shared values don't have a lifetime, they are basically the
suspend
equivalent of
by lazy
. As soon as the value has been computed, they cannot do anything anymore. Can you explain what your use-case is? I think I would use a prepared value in this situation
d
Basically just putting up a test containers db, and taking it down at the end of the spec. It's a bit too expensive to take it down each test, so I'd just drop it's contents after each test.
c
The problem is that I don't actually know when the end of the tests happen. Prepared declares the tests to the runner, but the runner is entirely responsible for actually running them. A runner could decide to only run some tests (e.g. if there was an IntelliJ Plugin), so I can't just guess when the shared value isn't needed anymore. As far as I know, this shouldn't be a problem with testcontainers, because it has
ryuk
that will kill containers that are unused.
Maybe you could do this on top of prepared, though. Instantiate a shared resource, count how many prepared values are instantiated, and wait until they are all freed.
Copy code
class SharedFinalizer {
    val subscribers: HashSet<Uuid> = HashSet()
    val code: suspend () -> Unit,
} 

private val database by shared {
    val database = Database(…)
    val finalizer = SharedFinalizer { database.close() }
    database to finalizer
}

val useDatabase by prepared {
    val (database, finalizer) = database()
    val id = Uuid.randomUuid()

    finalizer.subscribers.add(id)

    cleanUp {
        finalizer.subscribers.remove(id)
        if (finalizer.susbcribers.isEmpty())
            finalizer.code()
    }

    database
}
With proper synchronization, this kind of system could be added to Prepared to create a
cleanUp
function in Shared, I think
d
That looks like a pretty nice technique! Maybe you're right in this particular case that ryuk will probably get rid of the container, though. This might be useful in other cases, though, thanks!
c
I tend to avoid using Shared when I can, I much prefer Prepared. If you think this is worth having for interop with TestContainers, you can create an issue for it 🙂
Also, it may be worth having a
compat-testcontainer
module if there are many such utilities…
Personally, I prefer using docker-compose than testcontainers, so I don't have much experience with it
😮 1
d
It's pretty handy, especially when you have all those modules for different container types that give some interaction with the container (setting db user, pass, initScripts, dbName...) and it's configurations (host/port etc...). When using docker-compose, you'd need to run that in a shell, manage a yaml file with the configs and then hard code the same ones in the test (or parse the yaml... 🙃)
🙃 1
c
It could make sense to have a first-party
by testContainer
🤔
🤔 1
if you end up having nice utilities