summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNoah Kantrowitz <noah@coderanger.net>2015-07-31 14:45:34 -0700
committerNoah Kantrowitz <noah@coderanger.net>2015-07-31 14:45:34 -0700
commit63711b9da81c9db8466a2c45670f8d94cfdaac68 (patch)
tree64e5eb035cda1084848e285de3d49e83107821a1
parent85d3dfb6a361c774b6a1e4d4e437b836d5dd19cc (diff)
downloadchef-63711b9da81c9db8466a2c45670f8d94cfdaac68.tar.gz
Support forwards compatibility for event sinks.
We can add new arguments and events without breaking compat as long as the new arguments are added at the end. The new args will be silently trimmed for sending to older event sinks, and new event types will be ignored.
-rw-r--r--lib/chef/event_dispatch/dispatcher.rb12
-rw-r--r--spec/unit/event_dispatch/dispatcher_spec.rb23
2 files changed, 32 insertions, 3 deletions
diff --git a/lib/chef/event_dispatch/dispatcher.rb b/lib/chef/event_dispatch/dispatcher.rb
index 370f8c51b4..9e17d78507 100644
--- a/lib/chef/event_dispatch/dispatcher.rb
+++ b/lib/chef/event_dispatch/dispatcher.rb
@@ -28,7 +28,17 @@ class Chef
# Define a method that will be forwarded to all
def self.def_forwarding_method(method_name)
define_method(method_name) do |*args|
- @subscribers.each { |s| s.send(method_name, *args) }
+ @subscribers.each do |s|
+ # Skip new/unsupported event names.
+ if s.respond_to?(method_name)
+ mth = s.method(method_name)
+ # Anything with a *args is arity -1, so use all arguments.
+ arity = mth.arity < 0 ? args.length : mth.arity
+ # Trim arguments to match what the subscriber expects to allow
+ # adding new arguments without breaking compat.
+ mth.call(*args.take(arity))
+ end
+ end
end
end
diff --git a/spec/unit/event_dispatch/dispatcher_spec.rb b/spec/unit/event_dispatch/dispatcher_spec.rb
index 7e43b1933f..1014feea89 100644
--- a/spec/unit/event_dispatch/dispatcher_spec.rb
+++ b/spec/unit/event_dispatch/dispatcher_spec.rb
@@ -47,14 +47,33 @@ describe Chef::EventDispatch::Dispatcher do
expect(event_sink).to receive(:run_start).with("12.4.0")
dispatcher.run_start("12.4.0")
- expect(event_sink).to receive(:synchronized_cookbook).with("apache2")
- dispatcher.synchronized_cookbook("apache2")
+ cookbook_version = double("cookbook_version")
+ expect(event_sink).to receive(:synchronized_cookbook).with("apache2", cookbook_version)
+ dispatcher.synchronized_cookbook("apache2", cookbook_version)
exception = StandardError.new("foo")
expect(event_sink).to receive(:recipe_file_load_failed).with("/path/to/file.rb", exception)
dispatcher.recipe_file_load_failed("/path/to/file.rb", exception)
end
+ context "when an event sink has fewer arguments for an event" do
+ # Can't use a double because they don't report arity correctly.
+ let(:event_sink) do
+ Class.new(Chef::EventDispatch::Base) do
+ attr_reader :synchronized_cookbook_args
+ def synchronized_cookbook(cookbook_name)
+ @synchronized_cookbook_args = [cookbook_name]
+ end
+ end.new
+ end
+
+ it "trims the arugment list" do
+ cookbook_version = double("cookbook_version")
+ dispatcher.synchronized_cookbook("apache2", cookbook_version)
+ expect(event_sink.synchronized_cookbook_args).to eq ["apache2"]
+ end
+ end
+
end
end