From 52da142bf6b697c2a867a23e2545fb7646331ee8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Rasmusson?= Date: Sat, 26 Nov 2016 18:01:19 +0100 Subject: [PATCH] Queue the events in the event bus before the bus is started. To avoid that listeners miss events broadcast before the got a change to register themselves with the event bus, the bus needs to queue events until an exeplicit start message is received. --- lib/cucumber/core.rb | 7 ++++- lib/cucumber/core/event_bus.rb | 30 +++++++++++++++++-- spec/cucumber/core/event_bus_spec.rb | 35 +++++++++++++++++++---- spec/cucumber/core/report/summary_spec.rb | 5 +++- spec/cucumber/core_spec.rb | 7 ++--- 5 files changed, 70 insertions(+), 14 deletions(-) diff --git a/lib/cucumber/core.rb b/lib/cucumber/core.rb index a9faeaa8..c8fe7919 100644 --- a/lib/cucumber/core.rb +++ b/lib/cucumber/core.rb @@ -8,7 +8,7 @@ module Cucumber module Core - def execute(gherkin_documents, filters = [], event_bus = EventBus.new) + def execute(gherkin_documents, filters = [], event_bus = create_and_start_event_bus) yield event_bus if block_given? receiver = Test::Runner.new(event_bus) compile gherkin_documents, receiver, filters @@ -39,5 +39,10 @@ def compose(filters, last_receiver) end end + def create_and_start_event_bus + event_bus = EventBus.new + event_bus.start + event_bus + end end end diff --git a/lib/cucumber/core/event_bus.rb b/lib/cucumber/core/event_bus.rb index 12a1d0bd..455dd4ce 100644 --- a/lib/cucumber/core/event_bus.rb +++ b/lib/cucumber/core/event_bus.rb @@ -9,12 +9,22 @@ module Core # to subscribe to events that fire as your tests are executed. # class EventBus - attr_reader :event_types + attr_reader :event_types, :started + private :started # @param [Hash{Symbol => Class}] a hash of event types to use on the bus def initialize(registry = Events.registry) @event_types = registry.freeze @handlers = {} + @started = false + end + + def start + event_queue.each do |event| + do_broadcast(event) + end + reset_event_queue + @started = true end # Register for an event. The handler proc will be called back with each of the attributes @@ -29,7 +39,11 @@ def on(event_id, handler_object = nil, &handler_proc) # Broadcast an event def broadcast(event) raise ArgumentError, "Event type #{event.class} is not registered. Try one of these:\n#{event_types.values.join("\n")}" unless is_registered_type?(event.class) - handlers_for(event.class).each { |handler| handler.call(event) } + if started + do_broadcast(event) + else + event_queue << event + end end def method_missing(event_id, *args) @@ -45,6 +59,10 @@ def handlers_for(event_class) @handlers[event_class.to_s] ||= [] end + def do_broadcast(event) + handlers_for(event.class).each { |handler| handler.call(event) } + end + def is_registered_id?(event_id) event_types.keys.include?(event_id) end @@ -58,6 +76,14 @@ def validate_handler_and_event_id!(handler, event_id) raise ArgumentError, "Please use a symbol for the event_id" unless event_id.is_a?(Symbol) raise ArgumentError, "Event ID #{event_id} is not recognised. Try one of these:\n#{event_types.keys.join("\n")}" unless is_registered_id?(event_id) end + + def event_queue + @event_queue ||= [] + end + + def reset_event_queue + @event_queue = [] + end end end diff --git a/spec/cucumber/core/event_bus_spec.rb b/spec/cucumber/core/event_bus_spec.rb index f675d7d2..5802c248 100644 --- a/spec/cucumber/core/event_bus_spec.rb +++ b/spec/cucumber/core/event_bus_spec.rb @@ -18,6 +18,8 @@ class TestEvent < Core::Event.new(:some_attribute) context "broadcasting events" do + before(:each) { event_bus.start } + it "can broadcast by calling a method named after the event ID" do called = false event_bus.on(:test_event) {called = true } @@ -82,7 +84,23 @@ class TestEvent < Core::Event.new(:some_attribute) end + context "queuing events" do + + it "before the event bus is started, events are queued and broadcasted when started" do + called = false + event_bus.on(:test_event) {called = true } + event_bus.test_event + expect(called).to be false + event_bus.start + expect(called).to be true + end + + end + context "subscribing to events" do + + before(:each) { event_bus.start } + it "allows subscription by symbol (Event ID)" do received_payload = nil event_bus.on(:test_event) do |event| @@ -138,14 +156,19 @@ def on_test_event(event) end - it "will let you inspect the registry" do - expect(event_bus.event_types[:test_event]).to eq Events::TestEvent - end + context "event registry" do - it "won't let you modify the registry" do - expect { event_bus.event_types[:foo] = :bar }.to raise_error(RuntimeError) - end + before(:each) { event_bus.start } + it "will let you inspect the registry" do + expect(event_bus.event_types[:test_event]).to eq Events::TestEvent + end + + it "won't let you modify the registry" do + expect { event_bus.event_types[:foo] = :bar }.to raise_error(RuntimeError) + end + + end end end end diff --git a/spec/cucumber/core/report/summary_spec.rb b/spec/cucumber/core/report/summary_spec.rb index 24248c52..20338cdf 100644 --- a/spec/cucumber/core/report/summary_spec.rb +++ b/spec/cucumber/core/report/summary_spec.rb @@ -16,7 +16,10 @@ module Cucumber::Core::Report let(:duration) { double } let(:exception) { double } - before(:each) { @summary = Summary.new(event_bus) } + before(:each) do + @summary = Summary.new(event_bus) + event_bus.start + end context "test case summary" do let(:test_case) { double } diff --git a/spec/cucumber/core_spec.rb b/spec/cucumber/core_spec.rb index 5b66c6ff..7eb1a164 100644 --- a/spec/cucumber/core_spec.rb +++ b/spec/cucumber/core_spec.rb @@ -201,6 +201,9 @@ def expect_tag_excess(error_message) end describe "executing a test suite" do + let(:event_bus) { Core::EventBus.new } + + before(:each) { event_bus.start } it "fires events" do gherkin = gherkin do @@ -273,7 +276,6 @@ def expect_tag_excess(error_message) end end - event_bus = Core::EventBus.new report = Core::Report::Summary.new(event_bus) execute [gherkin], [Core::Test::Filters::ActivateStepsForSelfTest.new], event_bus @@ -317,7 +319,6 @@ def test_case(test_case) end logger = [] - event_bus = Core::EventBus.new report = Core::Report::Summary.new(event_bus) execute [gherkin], [WithAroundHooks.new(logger)], event_bus @@ -352,7 +353,6 @@ def test_case(test_case) end end - event_bus = Core::EventBus.new report = Core::Report::Summary.new(event_bus) execute [gherkin], [ Cucumber::Core::Test::TagFilter.new(['@a']) ], event_bus @@ -371,7 +371,6 @@ def test_case(test_case) end end - event_bus = Core::EventBus.new report = Core::Report::Summary.new(event_bus) execute [gherkin], [ Cucumber::Core::Test::NameFilter.new([/scenario/]) ], event_bus