Class: AMQP::SpecHelper::EventedExample

Inherits:
Object
  • Object
show all
Defined in:
lib/amqp-spec/evented_example.rb

Overview

Represents example running inside some type of event loop

Direct Known Subclasses

AMQPExample, EMExample

Instance Method Summary collapse

Constructor Details

#initialize(opts, example_group_instance, &block) ⇒ EventedExample

Create new evented example



11
12
13
# File 'lib/amqp-spec/evented_example.rb', line 11

def initialize(opts, example_group_instance, &block)
  @opts, @example_group_instance, @block = opts, example_group_instance, block
end

Instance Method Details

#done(delay = nil, &block) ⇒ Object

Breaks the event loop and finishes the spec.

This is under-implemented (generic) method that only implements optional delay. It should be given a block that does actual work of finishing up the event loop and cleaning any remaining artifacts.

Please redefine it inside descendant class and call super.



33
34
35
36
37
38
39
# File 'lib/amqp-spec/evented_example.rb', line 33

def done(delay=nil, &block)
  if delay
    EM.add_timer delay, &block
  else
    block.call
  end
end

#finish_em_loopObject

Stops EM event loop. It is called from #done



81
82
83
84
# File 'lib/amqp-spec/evented_example.rb', line 81

def finish_em_loop
  run_em_hooks :em_after
  EM.stop_event_loop if EM.reactor_running?
end

#finish_exampleObject

Called from #run_event_loop when event loop is stopped, but before the example returns. Descendant classes may redefine to clean up type-specific state.

Raises:

  • (@spec_exception)


90
91
92
# File 'lib/amqp-spec/evented_example.rb', line 90

def finish_example
  raise @spec_exception if @spec_exception
end

#run_em_hooks(type) ⇒ Object

Runs hooks of specified type (hopefully, inside the event loop)



43
44
45
46
47
48
49
50
51
# File 'lib/amqp-spec/evented_example.rb', line 43

def run_em_hooks(type)
  @example_group_instance.class.em_hooks[type].each do |hook|
    if @example_group_instance.respond_to? :instance_eval_without_event_loop
      @example_group_instance.instance_eval_without_event_loop(&hook)
    else
      @example_group_instance.instance_eval(&hook) #_with_rescue(&hook)
    end
  end
end

#run_em_loopObject

Runs given block inside EM event loop. Double-round exception handler needed because some of the exceptions bubble outside of event loop due to asynchronous nature of evented examples



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/amqp-spec/evented_example.rb', line 57

def run_em_loop
  begin
    EM.run do
      run_em_hooks :em_before

      @spec_exception = nil
      timeout(@opts[:spec_timeout]) if @opts[:spec_timeout]
      begin
        yield
      rescue Exception => @spec_exception
#              p "Inside loop, caught #{@spec_exception}"
        done # We need to properly terminate the event loop
      end
    end
  rescue Exception => @spec_exception
#          p "Outside loop, caught #{@spec_exception}"
    run_em_hooks :em_after # Event loop broken, but we still need to run em_after hooks
  ensure
    finish_example
  end
end

#timeout(spec_timeout) ⇒ Object

Sets timeout for currently running example



17
18
19
20
21
22
23
# File 'lib/amqp-spec/evented_example.rb', line 17

def timeout(spec_timeout)
  EM.cancel_timer(@spec_timer) if @spec_timer
  @spec_timer = EM.add_timer(spec_timeout) do
    @spec_exception = SpecTimeoutExceededError.new "Example timed out"
    done
  end
end