-
Notifications
You must be signed in to change notification settings - Fork 25
Improve garbage-collection/cleaning-up #335
Comments
I have wanted this too (while working on https://github.com/input-output-hk/ouroboros-network/). @edsko and I have come up with the following workaround: add a new command, e.g., |
I've used In older versions of the library, |
I think asking for a user function to do the cleanup is a good idea. During execution we should be careful to evaluate everything with proper exception handles (similar to what QuickCheck does http://hackage.haskell.org/package/QuickCheck-2.13.1/docs/src/Test.QuickCheck.Exception.html#tryEvaluate) and in case of exceptions we should do the cleanup before propagating. This is possible in all executeXX commands, since they live in IO, but not possible for all shrinkXX and generateXX commands. That's not an issue though, since there should be no running user recourses while shrinking or generating, User interrupts and async exceptions should also trigger the cleanup process before being propagated. I think the type of the user function should be something like |
Why is the model unreliable? Can we not make it:
? I'm a bit hesitant to expose |
In the parallel case
I replaced this with
and there were many failures. |
Yes, but that would be easy to change: pass in the model that's the result of executing the prefix. The problem to me seems to be that after executing one batch of suffixes, we cannot combine the resulting models and continue executing the next batch with the combined model. Unlike environments which have a monoid structure. Or is there some other problem you're seeing? |
I think it's the same problem. What you mention
can only work for the first suffix. Next suffixes can't get a correct inital Model, because as you mention we can;t combine Models. |
So another option would be to require |
Yes I don't think this will work either. Assume in Another option is to somehow have the user keep an environment which is Monoidal and make sure that this transitions correctly even in parallel tests. Something like it was done here https://github.com/input-output-hk/ouroboros-network/blob/master/ouroboros-consensus/test-util/Test/Util/RefEnv.hs#L35 and the model uses it in this way https://github.com/input-output-hk/ouroboros-network/blob/master/ouroboros-consensus/test-storage/Test/Ouroboros/Storage/ImmutableDB/StateMachine.hs#L301. Then this part of the Model transitions by a simple |
True, that's really ugly. How about getting the references from the history? Our run functions return histories already... Or build a model from the histories and then pass it to the cleanup function? |
Indeed, I think |
Why so? The history contains all commands and their responses, using the initial model and the transition functions should let us build a model similar to how This model might not be consistent unless the history Likewise in case of an exception (and a missing response) the reference has probably not been created and hence doesn't need to be cleaned up. It's up to the user to clean up inside the semantics function in this case. |
|
I'm not saying we should use |
|
Any of the possible interleavings should be good enough to rebuild the model, I think. |
Indeed, I wrote a function which does this and seems to work for my rqlite example. I was wondering though if it's too complicated for a recourse cleaning process. Do we have the guarantee that it will never fail, even after a test failure and for a random path of the interleavings tree? Maybe the cleanup, user-defined function should be |
From the users perspective it seems easier to me to write
I'm not certain of this, but it seems like something we can try and monitor. It should be easy to notice if we start leaking resources. In the case of exceptions being thrown in the semantics, there's a change of resource leaking, e.g.: resource <- acquireResource
error "This will cause a resource leak!"
return (Reference (Concrete resource)) I don't see how we can get around this problem though. I think in this case we need to rely on the user cleaning up in the semantics. |
I agree that it's the users's responsibility to handle exceptions in the semantics. I have done exactly this with brackets at my rqlite tests https://github.com/advancedtelematic/quickcheck-state-machine/blob/rqlite/test/RQlite.hs#L359. About the type of the cleanup function I don't have a strong opinion, I have tried both and they work the same https://github.com/advancedtelematic/quickcheck-state-machine/blob/rqlite/test/RQlite.hs#L443 and https://github.com/advancedtelematic/quickcheck-state-machine/blob/rqlite/test/RQlite.hs#L453 |
Also, the cleanup works when I ^C the tests. Although maybe I need to always mask async exceptions when I run the cleanup.. |
I think this is a very common issue many users face: Since q-s-m is used to test monadic code, it's possible that there is some interference between consecutive tests, or betweeen shrinking trials and proper cleaning up of resources is hard.
I faced this issue mainly on my rqlite tests https://github.com/advancedtelematic/quickcheck-state-machine/tree/rqlite, where I spawn new unix processes which listen on ports.
The solution I found there was to use the final Model returned from
runCommands
and do the cleaning up using this. For the parallel case, I extended therunParallelCommands
, so that it also returns the finalEnvironment
and do the cleanup. It works, but if the re is an unexpected exception the cleanup won't happen. That's why I have disabled shrinking for now.Another idea, is to get a cleanup function from the user and install handlers whenever suitable. Not sure how feasible this is and how big of a breaking change.
The text was updated successfully, but these errors were encountered: