From b4beed548959ca63365ca3d799c59a155047b5ff Mon Sep 17 00:00:00 2001 From: Adam Jacob Date: Fri, 7 Mar 2008 17:28:27 -0800 Subject: Syntax is right in the recipes --- bin/marionette | 0 bin/marionette-dotgraph | 40 ++++++++++ docs/recipe.rb | 61 +++++++++++--- examples/mrepo/Rakefile | 0 examples/sample_recipe.rb | 69 ++++++++++++++++ lib/marionette/helper.rb | 24 ------ lib/marionette/mixin/check_arguments.rb | 33 ++++++++ lib/marionette/mixin/graph_resources.rb | 8 +- lib/marionette/recipe.rb | 34 ++++---- lib/marionette/resource.rb | 123 +++++++++++++++++++++++------ lib/marionette/resource/file.rb | 102 +++++++++++++----------- spec/lib/marionette/resource/zen_master.rb | 44 +++++++++++ spec/spec.opts | 5 ++ spec/spec_helper.rb | 2 + spec/unit/mixin/graph_resources_spec.rb | 41 ++++++++++ spec/unit/node.rb | 43 ++++++++++ spec/unit/recipe_spec.rb | 20 +---- spec/unit/resource/file_spec.rb | 44 +++++------ spec/unit/resource_spec.rb | 117 ++++++++++++++++++--------- tasks/rspec.rb | 52 +++++++++++- 20 files changed, 652 insertions(+), 210 deletions(-) delete mode 100644 bin/marionette create mode 100755 bin/marionette-dotgraph create mode 100644 examples/mrepo/Rakefile create mode 100644 examples/sample_recipe.rb delete mode 100644 lib/marionette/helper.rb create mode 100644 lib/marionette/mixin/check_arguments.rb create mode 100644 spec/lib/marionette/resource/zen_master.rb create mode 100644 spec/spec.opts create mode 100644 spec/unit/mixin/graph_resources_spec.rb create mode 100644 spec/unit/node.rb diff --git a/bin/marionette b/bin/marionette deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/bin/marionette-dotgraph b/bin/marionette-dotgraph new file mode 100755 index 0000000000..80e2f342d7 --- /dev/null +++ b/bin/marionette-dotgraph @@ -0,0 +1,40 @@ +#!/usr/bin/ruby +# +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# License:: GNU General Public License version 2 or later +# +# This program and entire repository is free software; you can +# redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software +# Foundation; either version 2 of the License, or any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +require File.join(File.dirname(__FILE__), "..", "lib", "marionette") +require 'rgl/dot' + +mr = Marionette::Recipe.new("test", "default", "node") +raise ArgumentError, "#{ARGV[0]} is not a file!" unless File.exists?(ARGV[0]) +mr.instance_eval(IO.read(ARGV[0]), ARGV[0], 1) +puts mr.inspect +puts mr.dg.directed? +puts mr.dg.acyclic? +tree = Array.new +mr.dg.depth_first_visit(:top) do |v| + tree << v +end +maybe = mr.dg.bfs_search_tree_from(:top) +puts maybe.acyclic? +puts maybe.directed? +puts maybe.topsort_iterator.to_a.join("\n") +maybe.write_to_graphic_file + diff --git a/docs/recipe.rb b/docs/recipe.rb index 6c06a403e4..66d8b4c089 100644 --- a/docs/recipe.rb +++ b/docs/recipe.rb @@ -5,22 +5,57 @@ include_recipe 'openldap::client' include_recipe 'openssh' include_recipe 'nscd' -remote_file "nsswitch.conf" do - path "/etc/nsswitch.conf" - source "nsswitch.conf" - module "openldap" - mode 0644 - owner "root" - group "root" +file "/etc/nsswitch.conf" { + insure = "present" + owner = "root" + group = "root" + mode = 0644 +} + +file "/etc/ldap.conf" { + insure = "present" + owner = "root" + group = "root" + mode = 0644 + requires = resources(:file => "/etc/nsswitch.conf") +} + +file "/etc/ldap.conf" do + insure = "present" + owner = "root" + group = "root" + mode = 0644 + requires = resources(:file => "/etc/nsswitch.conf") +end + +remote_file "nsswitch.conf" { + path "/etc/nsswitch.conf" + source "nsswitch.conf" + module "openldap" + mode 0644 + owner "root" + group "root" requires :file => "nsswitch-ldap-file", :exec => [ "one", "two" ] - requires = resource(:file => "nsswitch-ldap-file") - notifies = resource(:service => "nscd", :exec => [ "nscd-clear-passwd", "nscd-clear-group" ] ) - subscribes = + notifies :service => "nscd", :exec => [ "nscd-clear-passwd", "nscd-clear-group" ] + provider 'File::Rsync' +} + +remote_file "nsswitch.conf" { + path = "/etc/nsswitch.conf" + source = "nsswitch.conf" + module = "openldap" + mode = 0644 + owner = "root" + group = "root" + requires = resources :file => "nsswitch-ldap-file", + :exec => [ "one", "two" ] + notifies = resources :service => "nscd", + :exec => [ "nscd-clear-passwd", "nscd-clear-group" ] provider = 'File::Rsync' -end +} service "nscd" do |s| - s.ensure = "running" + s.insure = "running" end case node[:lsbdistid] @@ -36,7 +71,7 @@ when "CentOS" f.require = resource(:package => "nss_ldap") end package "nss_ldap" do |p| - p.ensure = "latest" + p.insure = "latest" end end diff --git a/examples/mrepo/Rakefile b/examples/mrepo/Rakefile new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/sample_recipe.rb b/examples/sample_recipe.rb new file mode 100644 index 0000000000..730d7d58ff --- /dev/null +++ b/examples/sample_recipe.rb @@ -0,0 +1,69 @@ +include_recipe "openldap" +include_recipe "openldap::client" +include_recipe "openldap::server" +include_recipe "resolver" +include_recipe "base" + +service "apache2" do + insure "running" + has_restart true +end + +file "/etc/nsswitch.conf" do + insure "present" + owner "root" + group "root" + mode 0644 + notify :restart, resources(:service => "openldap"), :immediately +end + +file "/etc/ldap.conf" do + insure "present" + owner "root" + group "root" + mode 0644 + requires resources(:file => "/etc/nsswitch.conf") +end + +file "/srv/monkey" do + insure "present" + owner "root" + group "root" + mode 0644 +end + +file "/srv/owl" do + insure "present" + owner "root" + group "root" + mode 0644 +end + +file "/srv/zen" do + insure "absent" +end + +# +# file "/srv/monkey" do |f| +# f.insure = "present" +# f.owner = "adam" +# f.group = "adam" +# f.mode = 0644 +# f.before = resources(:file => "/etc/nsswitch.conf") +# end +# +# file "/etc/ldap-nss.conf" do |f| +# f.insure = "present" +# f.owner = "root" +# f.group = "root" +# f.mode = 0644 +# f.notifies = :refresh, resources(:file => "/etc/ldap.conf") +# end +# +# file "/etc/coffee.conf" do |f| +# f.insure = "present" +# f.owner = "root" +# f.group = "root" +# f.mode = 0644 +# f.subscribes = :polio, resources(:file => "/etc/nsswitch.conf") +# end \ No newline at end of file diff --git a/lib/marionette/helper.rb b/lib/marionette/helper.rb deleted file mode 100644 index 922f9449e1..0000000000 --- a/lib/marionette/helper.rb +++ /dev/null @@ -1,24 +0,0 @@ -# Author:: Adam Jacob () -# Copyright:: Copyright (c) 2008 HJK Solutions, LLC -# License:: GNU General Public License version 2 or later -# -# This program and entire repository is free software; you can -# redistribute it and/or modify it under the terms of the GNU -# General Public License as published by the Free Software -# Foundation; either version 2 of the License, or any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -# - -class Marionette - module Helper - - end -end \ No newline at end of file diff --git a/lib/marionette/mixin/check_arguments.rb b/lib/marionette/mixin/check_arguments.rb new file mode 100644 index 0000000000..ba38e3e734 --- /dev/null +++ b/lib/marionette/mixin/check_arguments.rb @@ -0,0 +1,33 @@ +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# License:: GNU General Public License version 2 or later +# +# This program and entire repository is free software; you can +# redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software +# Foundation; either version 2 of the License, or any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +class Marionette + module Mixin + module CheckArguments + def check_symbol_or_string(to_check, field_name) + case to_check + when Symbol, String + true + else + raise ArgumentError, "you must pass a symbol or string to #{field_name}!" + end + end + end + end +end \ No newline at end of file diff --git a/lib/marionette/mixin/graph_resources.rb b/lib/marionette/mixin/graph_resources.rb index 0a9ebeab21..7721b5d91a 100644 --- a/lib/marionette/mixin/graph_resources.rb +++ b/lib/marionette/mixin/graph_resources.rb @@ -17,6 +17,11 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # +require 'rubygems' +require 'rgl/adjacency' +require 'rgl/topsort' +require 'rgl/dot' + class Marionette module Mixin module GraphResources @@ -26,7 +31,7 @@ class Marionette # Returns one or an Array of matching resources. # # Raises a Runtime Error if it can't find the resources you are looking for. - def resource(args) + def resources(args) unless args.kind_of?(Hash) raise ArgumentError, "resource requires a hash of :resources => names" end @@ -73,7 +78,6 @@ class Marionette end raise RuntimeError, msg end - results.length == 1 ? results[0][:object] : results.collect { |r| r[:object] } end end diff --git a/lib/marionette/recipe.rb b/lib/marionette/recipe.rb index 7a9dc916de..e008400d55 100644 --- a/lib/marionette/recipe.rb +++ b/lib/marionette/recipe.rb @@ -18,18 +18,14 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # -require 'rubygems' -require 'rgl/adjacency' -require 'rgl/topsort' - class Marionette class Recipe include Marionette::Mixin::GraphResources - attr_accessor :module_name, :recipe_name, :recipe, :node, :dg + attr_accessor :module_name, :recipe_name, :recipe, :node, :dg, :deps - def initialize(module_name, recipe_name, node, dg=nil) + def initialize(module_name, recipe_name, node, dg=nil, deps=nil) @module_name = module_name @recipe_name = recipe_name @node = node @@ -39,7 +35,13 @@ class Marionette @dg = RGL::DirectedAdjacencyGraph.new() @dg.add_vertex(:top) end + if deps + @deps = deps + else + @deps = RGL::DirectedAdjacencyGraph.new() + end @last_resource = :top + @in_order = Array.new end def method_missing(method_symbol, *args, &block) @@ -54,25 +56,19 @@ class Marionette end begin args << @dg + args << @deps resource = eval(rname).new(*args) - resource.run(block) if Kernel.block_given? + resource.instance_eval(&block) rescue Exception => e - raise NameError, "Cannot find #{rname} for #{method_name}\nOriginal: #{e.to_s}" if e.kind_of?(NameError) - raise e + if e.kind_of?(NameError) && e.to_s =~ /Marionette::Resource/ + raise NameError, "Cannot find #{rname} for #{method_name}\nOriginal: #{e.to_s}" + else + raise e + end end @dg.add_vertex(resource) @dg.add_edge(@last_resource, resource) @last_resource = resource end - - private - def check_symbol_or_string(to_check, field_name) - case to_check - when Symbol, String - true - else - raise ArgumentError, "you must pass a symbol or string to #{field_name}!" - end - end end end \ No newline at end of file diff --git a/lib/marionette/resource.rb b/lib/marionette/resource.rb index f7ca861ccf..3100c2d7cb 100644 --- a/lib/marionette/resource.rb +++ b/lib/marionette/resource.rb @@ -17,6 +17,7 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # +require 'rubygems' require 'yaml' class Marionette @@ -24,58 +25,130 @@ class Marionette include Marionette::Mixin::GraphResources - attr_accessor :before, :requires, :notifies, :subscribes, :tag - attr_reader :name, :alias, :noop, :tag, :resource_name, :dg + attr_accessor :tag, :actions + attr_reader :name, :noop, :tag, :resource_name, :dg, :deps, :notifies, :subscribes - def initialize(name, dg=nil) + def initialize(name, dg=nil, deps=nil) @name = name if dg @dg = dg else @dg = RGL::DirectedAdjacencyGraph.new() - @dg.add_vertex(:top) end - @tag = Array.new - @alias = nil + if deps + @deps = deps + else + @deps = RGL::DirectedAdjacencyGraph.new() + end + @tag = [ name.to_s ] @noop = nil @tag = nil @before = nil - @tag = nil + @actions = Hash.new end - def name=(name) - raise ArgumentError, "name must be a string!" unless name.kind_of?(String) - @name = name + def name(name=nil) + set_if_args(@name, name) do + raise ArgumentError, "name must be a string!" unless name.kind_of?(String) + @name = name + end end - def alias=(alias_name) - raise ArgumentError, "alias must be a string!" unless alias_name.kind_of?(String) - @alias = alias_name + def noop(tf=nil) + set_if_args(@noop, tf) do + raise ArgumentError, "noop must be true or false!" unless tf == true || tf == false + @noop = tf + end end - def noop=(tf) - raise ArgumentError, "noop must be true or false!" unless tf == true || tf == false - @noop = tf + def requires(resources=nil) + rarray = resources.kind_of?(Array) ? resources : [ resources ] + rarray.each do |resource| + @deps.add_vertex(self) + @deps.add_vertex(resource) + @deps.add_edge(resource, self) + end + true + end + + def before(resources) + rarray = resources.kind_of?(Array) ? resources : [ resources ] + rarray.each do |resource| + @deps.add_vertex(self) + @deps.add_vertex(resource) + @deps.add_edge(self, resource) + end + true end - def tag=(args) - if args.kind_of?(Array) - args.each do |t| - @tag << t + def notifies(*notify_actions) + resources = notify_actions.pop + rarray = resources.kind_of?(Array) ? resources : [ resources ] + rarray.each do |resource| + @deps.add_vertex(self) + @deps.add_vertex(resource) + @deps.add_edge(self, resource) + notify_actions.each do |action| + action_sym = action.to_sym + if @actions.has_key?(action_sym) + @actions[action_sym] << resource + else + @actions[action_sym] = [ resource ] + end end - else - @tag << args end - @tag + true end - def run(ourblock) - ourblock.call + def subscribes(*subscribe_actions) + resources = subscribe_actions.pop + rarray = resources.kind_of?(Array) ? resources : [ resources ] + rarray.each do |resource| + @deps.add_vertex(self) + @deps.add_vertex(resource) + @deps.add_edge(resource, self) + subscribe_actions.each do |action| + action_sym = action.to_sym + if @actions.has_key?(action_sym) + resource.actions[action_sym] << self + else + resource.actions[action_sym] = [ self ] + end + end + end + true + end + + def tag(args=nil) + set_if_args(@tag, args) do + if args.kind_of?(Array) + args.each do |t| + @tag << t + end + else + @tag << args + end + @tag + end + end + + def to_s + "#{@resource_name} #{@name}" end def valid?() return false unless self.name true end + + private + def set_if_args(thing, arguments) + raise ArgumentError, "Must call set_if_args with a block!" unless Kernel.block_given? + if arguments != nil + yield(arguments) + else + thing + end + end end end \ No newline at end of file diff --git a/lib/marionette/resource/file.rb b/lib/marionette/resource/file.rb index 001474c8f9..f19b8f7b17 100644 --- a/lib/marionette/resource/file.rb +++ b/lib/marionette/resource/file.rb @@ -20,9 +20,9 @@ class Marionette class Resource class File < Marionette::Resource - attr_reader :backup, :checksum, :ensure, :group, :mode, :owner, :path + attr_reader :backup, :checksum, :insure, :group, :mode, :owner, :path - def initialize(name, dg=nil) + def initialize(name, dg=nil, deps=nil) @resource_name = :file super(name, dg) @path = name @@ -30,66 +30,80 @@ class Marionette @checksum = "md5sum" end - def backup=(arg) - case arg - when true, false, Integer - @backup = arg - else - raise ArgumentError, "backup must be true, false, or a number!" + def backup(arg=nil) + set_if_args(@backup, arg) do + case arg + when true, false, Integer + @backup = arg + else + raise ArgumentError, "backup must be true, false, or a number!" + end end end - def checksum=(arg) - case arg - when "md5sum", "mtime" - @checksum = arg - else - raise ArgumentError, "checksum must be md5sum or mtime!" + def checksum(arg=nil) + set_if_args(@checksum, arg) do + case arg + when "md5sum", "mtime" + @checksum = arg + else + raise ArgumentError, "checksum must be md5sum or mtime!" + end end end - def ensure=(arg) - case arg - when "absent", "present" - @ensure = arg - else - raise ArgumentError, "ensure must be absent or present!" + def insure(arg=nil) + set_if_args(@insure, arg) do + case arg + when "absent", "present" + @insure = arg + else + raise ArgumentError, "insure must be absent or present!" + end end end - def group=(arg) - case arg - when /^([a-z]|[A-Z]|[0-9]|_|-)+$/, Integer - @group = arg - else - raise ArgumentError, "group must match /^([a-z]|[A-Z]|[0-9]|_|-)$/, Integer!" + def group(arg=nil) + set_if_args(@group, arg) do + case arg + when /^([a-z]|[A-Z]|[0-9]|_|-)+$/, Integer + @group = arg + else + raise ArgumentError, "group must match /^([a-z]|[A-Z]|[0-9]|_|-)$/, Integer!" + end end end - def mode=(arg) - case "#{arg.to_s}" - when /^\d{3,4}$/ - @mode = arg - else - raise ArgumentError, "mode must be a valid unix file mode - 3 or 4 digets!" + def mode(arg=nil) + set_if_args(@mode, arg) do + case "#{arg.to_s}" + when /^\d{3,4}$/ + @mode = arg + else + raise ArgumentError, "mode must be a valid unix file mode - 3 or 4 digets!" + end end end - def owner=(arg) - case arg - when /^([a-z]|[A-Z]|[0-9]|_|-)+$/, Integer - @group = arg - else - raise ArgumentError, "group must match /^([a-z]|[A-Z]|[0-9]|_|-)$/, Integer!" + def owner(arg=nil) + set_if_args(@owner, arg) do + case arg + when /^([a-z]|[A-Z]|[0-9]|_|-)+$/, Integer + @owner = arg + else + raise ArgumentError, "group must match /^([a-z]|[A-Z]|[0-9]|_|-)$/, Integer!" + end end end - def path=(arg) - case arg - when String - @path = arg - else - raise ArgumentError, "path must be a string!" + def path(arg=nil) + set_if_args(@path, arg) do + case arg + when String + @path = arg + else + raise ArgumentError, "path must be a string!" + end end end diff --git a/spec/lib/marionette/resource/zen_master.rb b/spec/lib/marionette/resource/zen_master.rb new file mode 100644 index 0000000000..31b300d841 --- /dev/null +++ b/spec/lib/marionette/resource/zen_master.rb @@ -0,0 +1,44 @@ +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# License:: GNU General Public License version 2 or later +# +# This program and entire repository is free software; you can +# redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software +# Foundation; either version 2 of the License, or any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +class Marionette + class Resource + class ZenMaster < Marionette::Resource + attr_reader :peace + + def initialize(name, dg=nil, deps=nil) + @resource_name = :zen_master + super(name, dg) + end + + def peace(tf) + @peace = tf + end + + def something(arg=nil) + set_if_args(@something, arg) do + case arg + when true, false + @something = arg + end + end + end + end + end +end \ No newline at end of file diff --git a/spec/spec.opts b/spec/spec.opts new file mode 100644 index 0000000000..f94cf2d923 --- /dev/null +++ b/spec/spec.opts @@ -0,0 +1,5 @@ +--color +--format +progress +--loadby +mtime diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 314c81a5d9..452da0c2a3 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -18,3 +18,5 @@ # require File.join(File.dirname(__FILE__), "..", "lib", "marionette") +Dir[File.join(File.dirname(__FILE__), 'lib', '**', '*.rb')].sort.each { |lib| require lib } + diff --git a/spec/unit/mixin/graph_resources_spec.rb b/spec/unit/mixin/graph_resources_spec.rb new file mode 100644 index 0000000000..9fbb4f4c3e --- /dev/null +++ b/spec/unit/mixin/graph_resources_spec.rb @@ -0,0 +1,41 @@ +# +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# License:: GNU General Public License version 2 or later +# +# This program and entire repository is free software; you can +# redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software +# Foundation; either version 2 of the License, or any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +require File.join(File.dirname(__FILE__), "..", "..", "spec_helper") + +describe Marionette::Mixin::GraphResources do + it "should find a resource by symbol and name, or array of names" do + @recipe = Marionette::Recipe.new("one", "two", "three") + %w{monkey dog cat}.each do |name| + @recipe.zen_master name do + peace = true + end + end + doggie = @recipe.resources(:zen_master => "dog") + doggie.name.should eql("dog") # clever, I know + multi_zen = [ "dog", "monkey" ] + zen_array = @recipe.resources(:zen_master => multi_zen) + zen_array.length.should eql(2) + zen_array.each_index do |i| + zen_array[i].name.should eql(multi_zen[i]) + zen_array[i].resource_name.should eql(:zen_master) + end + end +end \ No newline at end of file diff --git a/spec/unit/node.rb b/spec/unit/node.rb new file mode 100644 index 0000000000..57c8cdd7f1 --- /dev/null +++ b/spec/unit/node.rb @@ -0,0 +1,43 @@ +# Author:: Adam Jacob () +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# License:: GNU General Public License version 2 or later +# +# This program and entire repository is free software; you can +# redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software +# Foundation; either version 2 of the License, or any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +require File.join(File.dirname(__FILE__), "..", "spec_helper") + +describe Marionette::Node do + before(:each) do + @node = Marionette::Node.new("latte") + end + + it "should have a name" do + @resource.name.should eql("latte") + end + + it "should create a new Marionette::Node" do + @resource.should be_a_kind_of(Marionette::Node) + end + + it "should not be valid without a name" do + lambda { @resource.name = nil }.should raise_error(ArgumentError) + end + + it "should always have a string for name" do + lambda { @resource.name = Hash.new }.should raise_error(ArgumentError) + end + +end \ No newline at end of file diff --git a/spec/unit/recipe_spec.rb b/spec/unit/recipe_spec.rb index 66c6095ffc..69f70e6862 100644 --- a/spec/unit/recipe_spec.rb +++ b/spec/unit/recipe_spec.rb @@ -19,24 +19,6 @@ require File.join(File.dirname(__FILE__), "..", "spec_helper") -class Marionette - class Resource - class ZenMaster < Marionette::Resource - attr_reader :peace - - def initialize(name, dg) - @resource_name = :zen_master - super(name, dg) - end - - def peace=(tf) - @peace = tf - end - end - end -end - - describe Marionette::Recipe do before(:each) do @recipe = Marionette::Recipe.new("hjk", "test", "node") @@ -89,7 +71,7 @@ zen_master "gnome" do end CODE lambda { @recipe.instance_eval(code) }.should_not raise_error - @recipe.resource(:zen_master => "gnome").name.should eql("gnome") + @recipe.resources(:zen_master => "gnome").name.should eql("gnome") end end \ No newline at end of file diff --git a/spec/unit/resource/file_spec.rb b/spec/unit/resource/file_spec.rb index 633805b56c..62b6498473 100644 --- a/spec/unit/resource/file_spec.rb +++ b/spec/unit/resource/file_spec.rb @@ -39,10 +39,10 @@ describe Marionette::Resource::File do end it "should only accept true, false, or a number for backup" do - lambda { @resource.backup = true }.should_not raise_error(ArgumentError) - lambda { @resource.backup = false }.should_not raise_error(ArgumentError) - lambda { @resource.backup = 10 }.should_not raise_error(ArgumentError) - lambda { @resource.backup = "blues" }.should raise_error(ArgumentError) + lambda { @resource.backup true }.should_not raise_error(ArgumentError) + lambda { @resource.backup false }.should_not raise_error(ArgumentError) + lambda { @resource.backup 10 }.should_not raise_error(ArgumentError) + lambda { @resource.backup "blues" }.should raise_error(ArgumentError) end it "should use the md5sum for checking changes by default" do @@ -50,33 +50,33 @@ describe Marionette::Resource::File do end it "should accept md5sum or mtime for checksum" do - lambda { @resource.checksum = "md5sum" }.should_not raise_error(ArgumentError) - lambda { @resource.checksum = "mtime" }.should_not raise_error(ArgumentError) - lambda { @resource.checksum = "blues" }.should raise_error(ArgumentError) + lambda { @resource.checksum "md5sum" }.should_not raise_error(ArgumentError) + lambda { @resource.checksum "mtime" }.should_not raise_error(ArgumentError) + lambda { @resource.checksum "blues" }.should raise_error(ArgumentError) end - it "should accept absent or present for ensure" do - lambda { @resource.ensure = "absent" }.should_not raise_error(ArgumentError) - lambda { @resource.ensure = "present" }.should_not raise_error(ArgumentError) - lambda { @resource.ensure = "blues" }.should raise_error(ArgumentError) + it "should accept absent or present for insure" do + lambda { @resource.insure "absent" }.should_not raise_error(ArgumentError) + lambda { @resource.insure "present" }.should_not raise_error(ArgumentError) + lambda { @resource.insure "blues" }.should raise_error(ArgumentError) end it "should accept a group name or id for group" do - lambda { @resource.group = "root" }.should_not raise_error(ArgumentError) - lambda { @resource.group = 123 }.should_not raise_error(ArgumentError) - lambda { @resource.group = "root*goo" }.should raise_error(ArgumentError) + lambda { @resource.group "root" }.should_not raise_error(ArgumentError) + lambda { @resource.group 123 }.should_not raise_error(ArgumentError) + lambda { @resource.group "root*goo" }.should raise_error(ArgumentError) end it "should accept a valid unix file mode" do - lambda { @resource.mode = 0444 }.should_not raise_error(ArgumentError) - lambda { @resource.mode = 444 }.should_not raise_error(ArgumentError) - lambda { @resource.mode = 4 }.should raise_error(ArgumentError) + lambda { @resource.mode 0444 }.should_not raise_error(ArgumentError) + lambda { @resource.mode 444 }.should_not raise_error(ArgumentError) + lambda { @resource.mode 4 }.should raise_error(ArgumentError) end it "should accept a user name or id for owner" do - lambda { @resource.owner = "root" }.should_not raise_error(ArgumentError) - lambda { @resource.owner = 123 }.should_not raise_error(ArgumentError) - lambda { @resource.owner = "root*goo" }.should raise_error(ArgumentError) + lambda { @resource.owner "root" }.should_not raise_error(ArgumentError) + lambda { @resource.owner 123 }.should_not raise_error(ArgumentError) + lambda { @resource.owner "root*goo" }.should raise_error(ArgumentError) end it "should use the object name as the path by default" do @@ -84,8 +84,8 @@ describe Marionette::Resource::File do end it "should accept a string as the path" do - lambda { @resource.path = "/tmp" }.should_not raise_error(ArgumentError) - lambda { @resource.path = Hash.new }.should raise_error(ArgumentError) + lambda { @resource.path "/tmp" }.should_not raise_error(ArgumentError) + lambda { @resource.path Hash.new }.should raise_error(ArgumentError) end end \ No newline at end of file diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb index 3d4b8bfa66..ccabda6043 100644 --- a/spec/unit/resource_spec.rb +++ b/spec/unit/resource_spec.rb @@ -33,54 +33,93 @@ describe Marionette::Resource do end it "should not be valid without a name" do - lambda { @resource.name = nil }.should raise_error(ArgumentError) + lambda { @resource.name false }.should raise_error(ArgumentError) end it "should always have a string for name" do - lambda { @resource.name = Hash.new }.should raise_error(ArgumentError) + lambda { @resource.name Hash.new }.should raise_error(ArgumentError) end - it "should have a string for alias" do - lambda { @resource.alias = nil }.should raise_error(ArgumentError) - lambda { @resource.alias = 'foo' }.should_not raise_error(ArgumentError) - @resource.alias.should eql("foo") + it "should accept true or false for noop" do + lambda { @resource.noop true }.should_not raise_error(ArgumentError) + lambda { @resource.noop false }.should_not raise_error(ArgumentError) + lambda { @resource.noop "eat it" }.should raise_error(ArgumentError) end - it "should accept true or false for noop" do - lambda { @resource.noop = true }.should_not raise_error(ArgumentError) - lambda { @resource.noop = false }.should_not raise_error(ArgumentError) - lambda { @resource.noop = "eat it" }.should raise_error(ArgumentError) + it "should make itself dependent on required resources" do + lambda { + @resource.dg.add_vertex(Marionette::Resource::ZenMaster.new("coffee")) + }.should_not raise_error + lambda { + @resource.requires @resource.resources(:zen_master => "coffee") + }.should_not raise_error + + @resource.deps.topsort_iterator.to_a[0].name.should eql("coffee") + @resource.deps.topsort_iterator.to_a[1].name.should eql("funk") + end + + it "should make before resources appear later in the graph" do + lambda { + @resource.dg.add_vertex(Marionette::Resource::ZenMaster.new("coffee")) + }.should_not raise_error + lambda { + @resource.before @resource.resources(:zen_master => "coffee") + }.should_not raise_error + + @resource.deps.topsort_iterator.to_a[0].name.should eql("funk") + @resource.deps.topsort_iterator.to_a[1].name.should eql("coffee") + end + + it "should make notified resources appear in the actions hash" do + @resource.dg.add_vertex(Marionette::Resource::ZenMaster.new("coffee")) + @resource.notifies :reload, @resource.resources(:zen_master => "coffee") + @resource.actions[:reload][0].name.should eql("coffee") + end + + it "should make notified resources happen later in the graph" do + @resource.dg.add_vertex(Marionette::Resource::ZenMaster.new("coffee")) + @resource.notifies :reload, @resource.resources(:zen_master => "coffee") + @resource.deps.topsort_iterator.to_a[0].name.should eql("funk") + @resource.deps.topsort_iterator.to_a[1].name.should eql("coffee") end - it "should serialize to yaml" do - yaml_output = <<-DESC ---- !ruby/object:Marionette::Resource -alias: -before: -name: funk -noop: -notify: -require: -subscribe: -tag: -DESC - @resource.to_yaml.should eql(yaml_output) - end + it "should make subscribed resources appear in the actions hash" do + @resource.dg.add_vertex(Marionette::Resource::ZenMaster.new("coffee")) + zr = @resource.resources(:zen_master => "coffee") + @resource.subscribes :reload, zr + zr.actions[:reload][0].name.should eql("funk") + end + + it "should make subscribed resources happen earlier in the graph" do + @resource.dg.add_vertex(Marionette::Resource::ZenMaster.new("coffee")) + zr = @resource.resources(:zen_master => "coffee") + @resource.subscribes :reload, zr + @resource.deps.topsort_iterator.to_a[1].name.should eql("funk") + @resource.deps.topsort_iterator.to_a[0].name.should eql("coffee") + end - it "should find a resource by symbol and name, or array of names" do - # %w{monkey dog cat}.each do |name| - # @recipe.zen_master name do - # peace = true - # end - # end - # doggie = @recipe.resource(:zen_master => "dog") - # doggie.name.should eql("dog") # clever, I know - # multi_zen = [ "dog", "monkey" ] - # zen_array = @recipe.resource(:zen_master => multi_zen) - # zen_array.length.should eql(2) - # zen_array.each_index do |i| - # zen_array[i].name.should eql(multi_zen[i]) - # zen_array[i].resource_name.should eql(:zen_master) - # end + it "should return a value if not defined" do + zm = Marionette::Resource::ZenMaster.new("coffee") + zm.something(true).should eql(true) + zm.something.should eql(true) + zm.something(false).should eql(false) + zm.something.should eql(false) end + +# it "should serialize to yaml" do +# yaml_output = <<-DESC +#--- !ruby/object:Marionette::Resource +#alias: +#before: +#name: funk +#noop: +#notify: +#require: +#subscribe: +#tag: +#DESC +# @resource.to_yaml.should eql(yaml_output) +# end + + end \ No newline at end of file diff --git a/tasks/rspec.rb b/tasks/rspec.rb index f3c2d7d25b..077840d31d 100644 --- a/tasks/rspec.rb +++ b/tasks/rspec.rb @@ -2,7 +2,53 @@ require 'rubygems' require 'rake' require 'spec/rake/spectask' -desc "Run all examples" -Spec::Rake::SpecTask.new('spec') do |t| - t.spec_files = FileList[File.join(File.dirname(__FILE__), "..", "spec", "**", "*.rb")] +#desc "Run all examples" +#Spec::Rake::SpecTask.new('spec') do |t| +# t.spec_files = FileList[File.join(File.dirname(__FILE__), "..", "spec", "**", "*.rb")] +#end + +require 'spec/rake/spectask' +require 'spec/translator' + +MARIONETTE_ROOT = File.join(File.dirname(__FILE__), "..") + +task :default => :spec + +desc "Run all specs in spec directory" +Spec::Rake::SpecTask.new(:spec) do |t| + t.spec_opts = ['--options', "\"#{MARIONETTE_ROOT}/spec/spec.opts\""] + t.spec_files = FileList['spec/**/*_spec.rb'] end + +namespace :spec do + desc "Run all specs in spec directory with RCov" + Spec::Rake::SpecTask.new(:rcov) do |t| + t.spec_opts = ['--options', "\"#{MARIONETTE_ROOT}/spec/spec.opts\""] + t.spec_files = FileList['spec/**/*_spec.rb'] + t.rcov = true + t.rcov_opts = lambda do + IO.readlines("#{MARIONETTE_ROOT}/spec/rcov.opts").map {|l| l.chomp.split " "}.flatten + end + end + + desc "Print Specdoc for all specs" + Spec::Rake::SpecTask.new(:doc) do |t| + t.spec_opts = ["--format", "specdoc", "--dry-run"] + t.spec_files = FileList['spec/**/*_spec.rb'] + end + + [:unit].each do |sub| + desc "Run the specs under spec/#{sub}" + Spec::Rake::SpecTask.new(sub) do |t| + t.spec_opts = ['--options', "\"#{MARIONETTE_ROOT}/spec/spec.opts\""] + t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"] + end + end + + desc "Translate/upgrade specs using the built-in translator" + task :translate do + translator = ::Spec::Translator.new + dir = MARIONETTE_ROOT + '/spec' + translator.translate(dir, dir) + end +end \ No newline at end of file -- cgit v1.2.1