From 008b1d19c3b7ac771a12af6a5d0f78c1b86a33ed Mon Sep 17 00:00:00 2001 From: Andrew Crump Date: Tue, 5 Jun 2012 08:30:06 +0100 Subject: [PATCH] Subscription support, refs #31. --- lib/foodcritic/api.rb | 7 +- spec/foodcritic/api_spec.rb | 306 +++++++++++++++++++++++++++++++++++- 2 files changed, 310 insertions(+), 3 deletions(-) diff --git a/lib/foodcritic/api.rb b/lib/foodcritic/api.rb index d6947992..e480c66b 100644 --- a/lib/foodcritic/api.rb +++ b/lib/foodcritic/api.rb @@ -185,7 +185,9 @@ def match(node) # @return [Array] A flat array of notifications. def notifications(ast) return [] unless ast.respond_to?(:xpath) - ast.xpath('//command[ident/@value="notifies"]').map do |notifies| + ast.xpath('//command[ident/@value="notifies" or + ident/@value="subscribes"]').map do |notifies| + params = notifies.xpath('descendant::method_add_arg[fcall/ident/ @value="resources"]/descendant::assoc_new') timing = notifies.xpath('args_add_block/args_add/symbol_literal[last()]/ @@ -203,7 +205,7 @@ def notifications(ast) end { :type => - :notifies, + notifies.xpath('ident/@value[1]').to_s.to_sym, :resource_type => resource_type, :resource_name => resource_name, :action => @@ -211,6 +213,7 @@ def notifications(ast) :notification_timing => timing.empty? ? :delayed : timing.first.to_s.to_sym } + end.compact end diff --git a/spec/foodcritic/api_spec.rb b/spec/foodcritic/api_spec.rb index 30855248..75ae78bb 100644 --- a/spec/foodcritic/api_spec.rb +++ b/spec/foodcritic/api_spec.rb @@ -301,7 +301,17 @@ def parse_ast(str) end })).must_be_empty end - it "returns empty if only the action is provided" do + it "returns empty if no subscribes value is provided" do + api.notifications(parse_ast(%q{ + template "/etc/nscd.conf" do + source "nscd.conf" + owner "root" + group "root" + subscribes + end + })).must_be_empty + end + it "returns empty if only the notifies action is provided" do api.notifications(parse_ast(%q{ template "/etc/nscd.conf" do source "nscd.conf" @@ -311,6 +321,16 @@ def parse_ast(str) end })).must_be_empty end + it "returns empty if only the subscribes action is provided" do + api.notifications(parse_ast(%q{ + template "/etc/nscd.conf" do + source "nscd.conf" + owner "root" + group "root" + subscribes :restart + end + })).must_be_empty + end describe "returns empty if the service name is missing" do it "old-style notifications" do api.notifications(parse_ast(%q{ @@ -322,6 +342,16 @@ def parse_ast(str) end })).must_be_empty end + it "old-style subscriptions" do + api.notifications(parse_ast(%q{ + template "/etc/nscd.conf" do + source "nscd.conf" + owner "root" + group "root" + subscribes:restart, resources(:service) + end + })).must_be_empty + end it "new-style notifications" do api.notifications(parse_ast(%q{ template "/etc/nscd.conf" do @@ -332,6 +362,16 @@ def parse_ast(str) end })).must_be_empty end + it "new-style subscriptions" do + api.notifications(parse_ast(%q{ + template "/etc/nscd.conf" do + source "nscd.conf" + owner "root" + group "root" + subscribes:restart, "service" + end + })).must_be_empty + end end describe "returns empty if the resource type is missing" do it "old-style notifications" do @@ -344,6 +384,16 @@ def parse_ast(str) end })).must_be_empty end + it "old-style subscriptions" do + api.notifications(parse_ast(%q{ + template "/etc/nscd.conf" do + source "nscd.conf" + owner "root" + group "root" + subscribes :restart, resources("nscd") + end + })).must_be_empty + end it "new-style notifications" do api.notifications(parse_ast(%q{ template "/etc/nscd.conf" do @@ -354,6 +404,16 @@ def parse_ast(str) end })).must_be_empty end + it "new-style subscriptions" do + api.notifications(parse_ast(%q{ + template "/etc/nscd.conf" do + source "nscd.conf" + owner "root" + group "root" + subscribes :restart, "nscd" + end + })).must_be_empty + end end end it "understands the old-style notifications" do @@ -374,6 +434,24 @@ def parse_ast(str) }] ) end + it "understands the old-style subscriptions" do + api.notifications(parse_ast(%q{ + template "/etc/nscd.conf" do + source "nscd.conf" + owner "root" + group "root" + subscribes :restart, resources(:service => "nscd") + end + })).must_equal( + [{ + :type => :subscribes, + :action => :restart, + :resource_type => :service, + :resource_name => 'nscd', + :notification_timing => :delayed + }] + ) + end it "understands the new-style notifications" do api.notifications(parse_ast(%q{ template "/etc/nscd.conf" do @@ -392,6 +470,78 @@ def parse_ast(str) }] ) end + it "understands the new-style subscriptions" do + api.notifications(parse_ast(%q{ + template "/etc/nscd.conf" do + source "nscd.conf" + owner "root" + group "root" + subscribes :restart, "service[nscd]" + end + })).must_equal( + [{ + :type => :subscribes, + :action => :restart, + :resource_type => :service, + :resource_name => 'nscd', + :notification_timing => :delayed + }] + ) + end + describe "supports a resource both notifying and subscribing" do + it "old-style notifications" do + api.notifications(parse_ast(%q{ + template "/etc/nscd.conf" do + source "nscd.conf" + owner "root" + group "root" + notifies :restart, resources(:service => "nscd") + subscribes :create, resources(:template => "/etc/nscd.conf") + end + })).must_equal([ + { + :type => :notifies, + :action => :restart, + :resource_type => :service, + :resource_name => 'nscd', + :notification_timing => :delayed + }, + { + :type => :subscribes, + :action => :create, + :resource_type => :template, + :resource_name => '/etc/nscd.conf', + :notification_timing => :delayed + } + ]) + end + it "new-style notifications" do + api.notifications(parse_ast(%q{ + template "/etc/nscd.conf" do + source "nscd.conf" + owner "root" + group "root" + notifies :restart, "service[nscd]" + subscribes :create, "template[/etc/nscd.conf]" + end + })).must_equal([ + { + :type => :notifies, + :action => :restart, + :resource_type => :service, + :resource_name => 'nscd', + :notification_timing => :delayed + }, + { + :type => :subscribes, + :action => :create, + :resource_type => :template, + :resource_name => '/etc/nscd.conf', + :notification_timing => :delayed + } + ]) + end + end it "understands the old-style notifications with timing" do api.notifications(parse_ast(%q{ template "/etc/nscd.conf" do @@ -410,6 +560,24 @@ def parse_ast(str) }] ) end + it "understands the old-style subscriptions with timing" do + api.notifications(parse_ast(%q{ + template "/etc/nscd.conf" do + source "nscd.conf" + owner "root" + group "root" + subscribes :restart, resources(:service => "nscd"), :immediately + end + })).must_equal( + [{ + :type => :subscribes, + :action => :restart, + :resource_type => :service, + :resource_name => 'nscd', + :notification_timing => :immediately + }] + ) + end it "understands the new-style notifications with timing" do api.notifications(parse_ast(%q{ template "/etc/nscd.conf" do @@ -428,6 +596,24 @@ def parse_ast(str) }] ) end + it "understands the new-style subscriptions with timing" do + api.notifications(parse_ast(%q{ + template "/etc/nscd.conf" do + source "nscd.conf" + owner "root" + group "root" + subscribes :restart, "service[nscd]", :immediately + end + })).must_equal( + [{ + :type => :subscribes, + :action => :restart, + :resource_type => :service, + :resource_name => 'nscd', + :notification_timing => :immediately + }] + ) + end describe "can be passed an individual resource" do it "old-style notifications" do api.notifications(api.find_resources(parse_ast(%q{ @@ -445,6 +631,22 @@ def parse_ast(str) :resource_name => 'nscd', :notification_timing => :delayed} ]) end + it "old-style subscriptions" do + api.notifications(api.find_resources(parse_ast(%q{ + service "nscd" do + action :start + end + template "/etc/nscd.conf" do + source "nscd.conf" + owner "root" + group "root" + subscribes :restart, resources(:service => "nscd") + end + }), :type => :template).first).must_equal([ + {:type => :subscribes, :action => :restart, :resource_type => :service, + :resource_name => 'nscd', :notification_timing => :delayed} + ]) + end it "new-style notifications" do api.notifications(api.find_resources(parse_ast(%q{ service "nscd" do @@ -461,6 +663,22 @@ def parse_ast(str) :resource_name => 'nscd', :notification_timing => :delayed} ]) end + it "new-style subscriptions" do + api.notifications(api.find_resources(parse_ast(%q{ + service "nscd" do + action :start + end + template "/etc/nscd.conf" do + source "nscd.conf" + owner "root" + group "root" + subscribes :restart, "service[nscd]" + end + }), :type => :template).first).must_equal([ + {:type => :subscribes, :action => :restart, :resource_type => :service, + :resource_name => 'nscd', :notification_timing => :delayed} + ]) + end end describe "supports multiple notifications on a single resource" do it "old-style notifications" do @@ -481,6 +699,24 @@ def parse_ast(str) ] ) end + it "old-style subscriptions" do + api.notifications(parse_ast(%q{ + template "/etc/nscd.conf" do + source "nscd.conf" + owner "root" + group "root" + subscribes :stop, resources(:service => "nscd") + subscribes :start, resources(:service => "nscd") + end + })).must_equal( + [ + {:type => :subscribes, :action => :stop, :resource_type => :service, + :resource_name => 'nscd', :notification_timing => :delayed}, + {:type => :subscribes, :action => :start, :resource_type => :service, + :resource_name => 'nscd', :notification_timing => :delayed} + ] + ) + end it "new-style notifications" do api.notifications(parse_ast(%q{ template "/etc/nscd.conf" do @@ -499,6 +735,24 @@ def parse_ast(str) ] ) end + it "new-style subscriptions" do + api.notifications(parse_ast(%q{ + template "/etc/nscd.conf" do + source "nscd.conf" + owner "root" + group "root" + subscribes :stop, "service[nscd]" + subscribes :start, "service[nscd]" + end + })).must_equal( + [ + {:type => :subscribes, :action => :stop, :resource_type => :service, + :resource_name => 'nscd', :notification_timing => :delayed}, + {:type => :subscribes, :action => :start, :resource_type => :service, + :resource_name => 'nscd', :notification_timing => :delayed} + ] + ) + end end describe "understands style notifications for an execute resource" do it "old-style notifications" do @@ -512,6 +766,17 @@ def parse_ast(str) :resource_name => 'foo', :notification_timing => :delayed}] ) end + it "old-style subscriptions" do + api.notifications(parse_ast(%q{ + template "/tmp/foo.bar" do + source "foo.bar.erb" + subscribes :run, resources(:execute => "foo") + end + })).must_equal( + [{:type => :subscribes, :action => :run, :resource_type => :execute, + :resource_name => 'foo', :notification_timing => :delayed}] + ) + end it "old-style notifications" do api.notifications(parse_ast(%q{ template "/tmp/foo.bar" do @@ -523,6 +788,17 @@ def parse_ast(str) :resource_name => 'foo', :notification_timing => :delayed}] ) end + it "old-style subscriptions" do + api.notifications(parse_ast(%q{ + template "/tmp/foo.bar" do + source "foo.bar.erb" + subscribes :run, "execute[foo]" + end + })).must_equal( + [{:type => :subscribes, :action => :run, :resource_type => :execute, + :resource_name => 'foo', :notification_timing => :delayed}] + ) + end end describe "sets the notification timing to delayed if specified" do it "old-style notifications" do @@ -532,6 +808,13 @@ def parse_ast(str) end })).first[:notification_timing].must_equal(:delayed) end + it "old-style subscriptions" do + api.notifications(parse_ast(%q{ + template "/etc/foo.conf" do + subscribes :run, resources(execute => "robespierre"), :delayed + end + })).first[:notification_timing].must_equal(:delayed) + end it "new-style notifications" do api.notifications(parse_ast(%q{ template "/etc/foo.conf" do @@ -539,6 +822,13 @@ def parse_ast(str) end })).first[:notification_timing].must_equal(:delayed) end + it "new-style subscriptions" do + api.notifications(parse_ast(%q{ + template "/etc/foo.conf" do + subscribes :run, "execute[robespierre]", :delayed + end + })).first[:notification_timing].must_equal(:delayed) + end end describe "sets the notification timing to immediately if specified" do it "old-style notifications" do @@ -548,6 +838,13 @@ def parse_ast(str) end })).first[:notification_timing].must_equal(:immediately) end + it "old-style subscriptions" do + api.notifications(parse_ast(%q{ + template "/etc/foo.conf" do + subscribes :run, resources(execute => "robespierre"), :immediately + end + })).first[:notification_timing].must_equal(:immediately) + end it "new-style notifications" do api.notifications(parse_ast(%q{ template "/etc/foo.conf" do @@ -555,6 +852,13 @@ def parse_ast(str) end })).first[:notification_timing].must_equal(:immediately) end + it "new-style subscriptions" do + api.notifications(parse_ast(%q{ + template "/etc/foo.conf" do + subscribes :run, "execute[robespierre]", :immediately + end + })).first[:notification_timing].must_equal(:immediately) + end end end