Skip to content
This repository has been archived by the owner on Sep 19, 2020. It is now read-only.

Commit

Permalink
Support modern style of notifications, refs #31.
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrew Crump committed Jun 4, 2012
1 parent a68ce8a commit 109bd03
Show file tree
Hide file tree
Showing 2 changed files with 271 additions and 17 deletions.
29 changes: 22 additions & 7 deletions lib/foodcritic/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -179,24 +179,39 @@ def match(node)
:line => pos['line'].to_i, :column => pos['column'].to_i}
end

# Decode resource notifications.
#
# @param [Nokogiri::XML::Node] ast The AST to check for notifications.
# @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|
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()]/symbol/ident[1]/@value')
timing = notifies.xpath('args_add_block/args_add/symbol_literal[last()]/
symbol/ident[1]/@value')
if params.empty?
target = notifies.xpath('args_add_block/args_add/
descendant::tstring_content[1]/@value').to_s
match = target.match(/^([^\[]+)\[(.+)\]$/)
next unless match
resource_type, resource_name =
match.captures.tap{|m| m[0] = m[0].to_sym}
else
resource_type = params.xpath('symbol[1]/ident/@value').to_s.to_sym
resource_name = params.xpath('string_add[1]/tstring_content/@value').to_s
end
{
:type =>
:notifies,
:resource_type => resource_type,
:resource_name => resource_name,
:action =>
notifies.xpath('descendant::symbol[1]/ident/@value').to_s.to_sym,
:resource_type =>
params.xpath('symbol[1]/ident/@value').to_s.to_sym,
:resource_name =>
params.xpath('string_add[1]/tstring_content/@value').to_s,
:notification_timing => timing.empty? ? :delayed : timing.first.to_s.to_sym
:notification_timing =>
timing.empty? ? :delayed : timing.first.to_s.to_sym
}
end
end.compact
end

# Does the provided string look like an Operating System command? This is a
Expand Down
259 changes: 249 additions & 10 deletions spec/foodcritic/api_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,81 @@ def parse_ast(str)
it "returns empty if the provided AST does not support XPath" do
api.notifications(nil).must_be_empty
end
it "returns empty if there are no notifications" do
api.notifications(parse_ast(%q{
template "/etc/nscd.conf" do
source "nscd.conf"
owner "root"
group "root"
end
})).must_be_empty
end
describe "malformed syntax" do
it "returns empty if no notifies value is provided" do
api.notifications(parse_ast(%q{
template "/etc/nscd.conf" do
source "nscd.conf"
owner "root"
group "root"
notifies
end
})).must_be_empty
end
it "returns empty if only the action is provided" do
api.notifications(parse_ast(%q{
template "/etc/nscd.conf" do
source "nscd.conf"
owner "root"
group "root"
notifies :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{
template "/etc/nscd.conf" do
source "nscd.conf"
owner "root"
group "root"
notifies :restart, resources(:service)
end
})).must_be_empty
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"
end
})).must_be_empty
end
end
describe "returns empty if the resource type is missing" 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("nscd")
end
})).must_be_empty
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, "nscd"
end
})).must_be_empty
end
end
end
it "understands the old-style notifications" do
api.notifications(parse_ast(%q{
template "/etc/nscd.conf" do
Expand All @@ -299,23 +374,187 @@ def parse_ast(str)
}]
)
end
it "understands old-style notifications for an execute resource" do
it "understands the new-style notifications" do
api.notifications(parse_ast(%q{
template "/tmp/foo.bar" do
source "foo.bar.erb"
notifies :run, resources(:execute => "foo")
template "/etc/nscd.conf" do
source "nscd.conf"
owner "root"
group "root"
notifies :restart, "service[nscd]"
end
})).must_equal(
[{:type => :notifies, :action => :run, :resource_type => :execute,
:resource_name => 'foo', :notification_timing => :delayed}]
[{
:type => :notifies,
:action => :restart,
:resource_type => :service,
:resource_name => 'nscd',
:notification_timing => :delayed
}]
)
end
it "understands the old-style notifications with timing" do
api.notifications(parse_ast(%q{
template "/etc/nscd.conf" do
source "nscd.conf"
owner "root"
group "root"
notifies :restart, resources(:service => "nscd"), :immediately
end
})).must_equal(
[{
:type => :notifies,
:action => :restart,
:resource_type => :service,
:resource_name => 'nscd',
:notification_timing => :immediately
}]
)
end
it "sets the notification timing appropriately" do
it "understands the new-style notifications with timing" do
api.notifications(parse_ast(%q{
template "/etc/foo.conf" do
notifies :run, resources(execute => "robespierre"), :immediately
template "/etc/nscd.conf" do
source "nscd.conf"
owner "root"
group "root"
notifies :restart, "service[nscd]", :immediately
end
})).first[:notification_timing].must_equal(:immediately)
})).must_equal(
[{
:type => :notifies,
: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{
service "nscd" do
action :start
end
template "/etc/nscd.conf" do
source "nscd.conf"
owner "root"
group "root"
notifies :restart, resources(:service => "nscd")
end
}), :type => :template).first).must_equal([
{:type => :notifies, :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
action :start
end
template "/etc/nscd.conf" do
source "nscd.conf"
owner "root"
group "root"
notifies :restart, "service[nscd]"
end
}), :type => :template).first).must_equal([
{:type => :notifies, :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
api.notifications(parse_ast(%q{
template "/etc/nscd.conf" do
source "nscd.conf"
owner "root"
group "root"
notifies :stop, resources(:service => "nscd")
notifies :start, resources(:service => "nscd")
end
})).must_equal(
[
{:type => :notifies, :action => :stop, :resource_type => :service,
:resource_name => 'nscd', :notification_timing => :delayed},
{:type => :notifies, :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
source "nscd.conf"
owner "root"
group "root"
notifies :stop, "service[nscd]"
notifies :start, "service[nscd]"
end
})).must_equal(
[
{:type => :notifies, :action => :stop, :resource_type => :service,
:resource_name => 'nscd', :notification_timing => :delayed},
{:type => :notifies, :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
api.notifications(parse_ast(%q{
template "/tmp/foo.bar" do
source "foo.bar.erb"
notifies :run, resources(:execute => "foo")
end
})).must_equal(
[{:type => :notifies, :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
source "foo.bar.erb"
notifies :run, "execute[foo]"
end
})).must_equal(
[{:type => :notifies, :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
api.notifications(parse_ast(%q{
template "/etc/foo.conf" do
notifies :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
notifies :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
api.notifications(parse_ast(%q{
template "/etc/foo.conf" do
notifies :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
notifies :run, "execute[robespierre]", :immediately
end
})).first[:notification_timing].must_equal(:immediately)
end
end
end

Expand Down

0 comments on commit 109bd03

Please sign in to comment.