Hello Ian,
it's true that the wait_for(participant_name_as_a_symbol) might not be applicable in your case.
I use it with success in ruote's test suite, but it's using the Ruote::TestLogger instead of the Ruote::WaitLogger coming by default with the engine.
The TestLogger keeps track of seen messages, it's more reliable, for cases when the engine is faster than the wait_for() order. The symptom of "engine faster than wait_for()" is simply the wait_for() never returning since the message it's waiting for is gone.
To use the TestLogger, you have to make sure the worker/engine/storage uses it as the logger service, like in this example :
---8<---
@engine =
Ruote::Engine.new(
Ruote::Worker.new(
determine_storage(
's_logger' => [ 'ruote/log/test_logger', 'Ruote::TestLogger' ])))
--->8---
The downside is that this TestLogger is only meant for testing, its log of seen messages is not bound, if no wait_for 'consumes' it, it may grow too large.
> I see two potential solutions:
>
> 1. some way to "jump" the process instance to a given state, kind of
> like stubbing or database fixtures
There has already been demand for this kind of feature. It should be easy to wrap participants to force some of them to "fast forward". I will think about it, I think it's a necessary feature.
Somehow, it can already be realize by registering "fast forward" participant for the sake of the test.
> 2. some way to reliably detect and respond to engine events,
> effectively making my tests run synchronously with the engine (ie. get
> #wait_for working)
I could help if you tell me how (regex, absolute names) you register your participant and how you except to wait_for them.
> Unfortunately, I've no idea how I would approach either solution. Are
> there other solutions? Help approaching one of these?
There could be a third solution : since you are using StorageParticipant, you could extend it for your testing purposes.
see http://gist.github.com/416620 :
---8<---
class TestStorageParticipant < Ruote::StorageParticipant
def initialize (options)
super(options)
@seen = []
end
def consume (workitem)
@seen << workitem.dup
# dup in order to return the workitem as 'received' by the participant
super(workitem)
check_waiting
end
def wait_for (*participant_names)
@waiting = [ Thread.current, participant_names ]
check_waiting
Thread.stop if @waiting
Thread.current['__result__']
# return the waited for workitem as a result
end
protected
def check_waiting
return unless @waiting
while workitem = @seen.shift
break if check_workitem(workitem)
end
end
def check_workitem (workitem)
if @waiting[1].include?(workitem.participant_name)
thread = @waiting[0]
@waiting = nil
thread['__result__'] = workitem
thread.wakeup
true
else
false
end
end
end
--->8---
Warning : this is not tested, it's been written during a train ride (right now).
Your email made me realize I'm using sleep instead of wait_for in ruote-cukes :
http://github.com/jmettraux/ruote-cukes
I have to change that.
Glad to help, best regards,
--
John Mettraux - http://jmettraux.wordpress.com