diff options
-rw-r--r-- | CHANGELOG | 8 | ||||
-rwxr-xr-x | bin/puppet | 79 | ||||
-rw-r--r-- | lib/puppet/indirector.rb | 13 | ||||
-rw-r--r-- | lib/puppet/indirector/code/configuration.rb | 60 | ||||
-rw-r--r-- | lib/puppet/network/client/master.rb | 1 | ||||
-rw-r--r-- | lib/puppet/node/configuration.rb | 2 | ||||
-rwxr-xr-x | lib/puppet/node/facts.rb | 2 | ||||
-rw-r--r-- | lib/puppet/parser/compile.rb | 4 | ||||
-rw-r--r-- | lib/puppet/parser/interpreter.rb | 7 | ||||
-rwxr-xr-x | spec/unit/indirector/code/configuration.rb | 16 | ||||
-rwxr-xr-x | spec/unit/indirector/indirector.rb | 7 | ||||
-rwxr-xr-x | spec/unit/node/configuration.rb | 24 | ||||
-rwxr-xr-x | spec/unit/node/facts.rb | 15 | ||||
-rwxr-xr-x | spec/unit/parser/compile.rb | 10 | ||||
-rwxr-xr-x | spec/unit/parser/interpreter.rb | 23 | ||||
-rwxr-xr-x | test/language/compile.rb | 14 | ||||
-rwxr-xr-x | test/language/snippets.rb | 45 | ||||
-rwxr-xr-x | test/rails/configuration.rb | 1 |
18 files changed, 190 insertions, 141 deletions
@@ -1,4 +1,9 @@ -0.23.2 (misspiggy) + The --use-nodes and --no-nodes options are now obsolete. + Puppet automatically detects when nodes are defined, and if + they are defined it will require that a node be found, + else it will not look for a node nor will it fail if it + fails to find one. + Fixed #832. Added the '--no-daemonize' option to puppetd and puppetmasterd. NOTE: The default behavior of 'verbose' and 'debug' no longer cause puppetd and puppetmasterd to not @@ -10,6 +15,7 @@ Added shortname support to config.rb and refactored addargs +0.23.2 Fixed the problem in cron jobs where environment settings tended to multiple. (#749) diff --git a/bin/puppet b/bin/puppet index a87a07619..a5aa030ac 100755 --- a/bin/puppet +++ b/bin/puppet @@ -80,14 +80,16 @@ Puppet.settings.addargs(options) result = GetoptLong.new(*options) -debug = false -verbose = false -noop = false -logfile = false -loadclasses = false -logset = false +options = { + :debug => false, + :verbose => false, + :noop => false, + :logfile => false, + :loadclasses => false, + :logset => false, + :code => nil +} -code = nil master = { :Local => true @@ -107,19 +109,19 @@ begin exit end when "--use-nodes" - master[:UseNodes] = true + options[:UseNodes] = true when "--verbose" - verbose = true + options[:verbose] = true when "--debug" - debug = true + options[:debug] = true when "--execute" - code = arg + options[:code] = arg when "--loadclasses" - loadclasses = true + options[:loadclasses] = true when "--logdest" begin Puppet::Util::Log.newdestination(arg) - logset = true + options[:logset] = true rescue => detail $stderr.puts detail.to_s end @@ -139,7 +141,7 @@ if Puppet[:noop] Puppet[:show_diff] = true end -unless logset +unless options[:logset] Puppet::Util::Log.newdestination(:console) end @@ -148,9 +150,9 @@ server = nil Puppet.settraps -if debug +if options[:debug] Puppet::Util::Log.level = :debug -elsif verbose +elsif options[:verbose] Puppet::Util::Log.level = :info end @@ -162,18 +164,26 @@ end Puppet.genconfig Puppet.genmanifest -if code - master[:Code] = code +# Set our code or file to use. +if options[:code] or ARGV.length == 0 + Puppet::Node::Configuration.code = options[:code] || STDIN.read else - if ARGV.length > 0 - master[:Manifest] = ARGV.shift - else - master[:Code] = STDIN.read - end + Puppet[:manifest] = ARGV.shift end +# Collect our facts. +Puppet::Node::Facts.terminus_class = :code +facts = Puppet::Node::Facts.find("me") +facts.name = facts.values["hostname"] + +# Create our Node +node = Puppet::Node.new(facts.name) + +# Merge in the facts. +node.merge(facts.values) + # Allow users to load the classes that puppetd creates. -if loadclasses +if options[:loadclasses] file = Puppet[:classfile] if FileTest.exists?(file) unless FileTest.readable?(file) @@ -181,20 +191,21 @@ if loadclasses exit(63) end - master[:Classes] = File.read(file).split(/[\s\n]+/) + node.classes = File.read(file).split(/[\s\n]+/) end end +# Compile and apply the configuration +Puppet::Node::Configuration.terminus_class = :code + begin - server = Puppet::Network::Handler.master.new(master) - client = Puppet::Network::Client.master.new( - :Master => server, - :Cache => false - ) - if Puppet[:parseonly] - exit(0) - end - config = client.getconfig + # Compile our configuration + config = Puppet::Node::Configuration.find(node) + + # Translate it to a RAL configuration + config = config.extract_to_transportable.to_configuration + + # And apply it config.apply rescue => detail if Puppet[:trace] diff --git a/lib/puppet/indirector.rb b/lib/puppet/indirector.rb index 7821e809c..7ceaa43e2 100644 --- a/lib/puppet/indirector.rb +++ b/lib/puppet/indirector.rb @@ -15,7 +15,7 @@ module Puppet::Indirector # default, not the value -- if it's the value, then it gets # evaluated at parse time, which is before the user has had a chance # to override it. - def indirects(indirection) + def indirects(indirection, options = {}) raise(ArgumentError, "Already handling indirection for %s; cannot also handle %s" % [@indirection.name, indirection]) if defined?(@indirection) and @indirection # populate this class with the various new methods extend ClassMethods @@ -24,6 +24,17 @@ module Puppet::Indirector # instantiate the actual Terminus for that type and this name (:ldap, w/ args :node) # & hook the instantiated Terminus into this class (Node: @indirection = terminus) @indirection = Puppet::Indirector::Indirection.new(self, indirection) + + unless options.empty? + options.each do |param, value| + case param + when :terminus_class: @indirection.terminus_class = value + else + raise ArgumenError, "Invalid option '%s' to 'indirects'" % param + end + end + end + @indirection end module ClassMethods diff --git a/lib/puppet/indirector/code/configuration.rb b/lib/puppet/indirector/code/configuration.rb index 6d0317204..b3a4c67dd 100644 --- a/lib/puppet/indirector/code/configuration.rb +++ b/lib/puppet/indirector/code/configuration.rb @@ -15,21 +15,12 @@ class Puppet::Indirector::Code::Configuration < Puppet::Indirector::Code # Compile a node's configuration. def find(key, client = nil, clientip = nil) - # If we want to use the cert name as our key - if Puppet[:node_name] == 'cert' and client - key = client - end - - # Note that this is reasonable, because either their node source should actually - # know about the node, or they should be using the ``none`` node source, which - # will always return data. - unless node = Puppet::Node.search(key) - raise Puppet::Error, "Could not find node '%s'" % key + if key.is_a?(Puppet::Node) + node = key + else + node = find_node(key) end - # Add any external data to the node. - add_node_data(node) - configuration = compile(node) return configuration @@ -47,6 +38,11 @@ class Puppet::Indirector::Code::Configuration < Puppet::Indirector::Code @interpreter end + # Is our compiler part of a network, or are we just local? + def networked? + $0 =~ /puppetmasterd/ + end + # Return the configuration version. def version(client = nil, clientip = nil) if client and node = Puppet::Node.search(client) @@ -76,22 +72,17 @@ class Puppet::Indirector::Code::Configuration < Puppet::Indirector::Code end config = nil + loglevel = networked? ? :notice : :none + # LAK:FIXME This should log at :none when our client is # local, since we don't want 'puppet' (vs. puppetmasterd) to # log compile times. - benchmark(:notice, "Compiled configuration for %s" % node.name) do + benchmark(loglevel, "Compiled configuration for %s" % node.name) do begin config = interpreter.compile(node) rescue Puppet::Error => detail - if Puppet[:trace] - puts detail.backtrace - end - unless local? - Puppet.err detail.to_s - end - raise XMLRPC::FaultException.new( - 1, detail.to_s - ) + Puppet.err(detail.to_s) if networked? + raise end end @@ -117,6 +108,27 @@ class Puppet::Indirector::Code::Configuration < Puppet::Indirector::Code return Puppet::Parser::Interpreter.new(args) end + # Turn our host name into a node object. + def find_node(key) + # If we want to use the cert name as our key + # LAK:FIXME This needs to be figured out somehow, but it requires the routing. + #if Puppet[:node_name] == 'cert' and client + # key = client + #end + + # Note that this is reasonable, because either their node source should actually + # know about the node, or they should be using the ``none`` node source, which + # will always return data. + unless node = Puppet::Node.search(key) + raise Puppet::Error, "Could not find node '%s'" % key + end + + # Add any external data to the node. + add_node_data(node) + + node + end + # Initialize our server fact hash; we add these to each client, and they # won't change while we're running, so it's safe to cache the values. def set_server_facts @@ -150,7 +162,7 @@ class Puppet::Indirector::Code::Configuration < Puppet::Indirector::Code # LAK:FIXME This method should probably be part of the protocol, but it # shouldn't be here. def translate(config) - if local? + unless networked? config else CGI.escape(config.to_yaml(:UseBlock => true)) diff --git a/lib/puppet/network/client/master.rb b/lib/puppet/network/client/master.rb index f950a6059..989d6dca2 100644 --- a/lib/puppet/network/client/master.rb +++ b/lib/puppet/network/client/master.rb @@ -544,6 +544,7 @@ class Puppet::Network::Client::Master < Puppet::Network::Client end rescue => detail + puts detail.backtrace Puppet.err "Could not retrieve configuration: %s" % detail unless Puppet[:usecacheonfailure] diff --git a/lib/puppet/node/configuration.rb b/lib/puppet/node/configuration.rb index 3571eecda..084bdf880 100644 --- a/lib/puppet/node/configuration.rb +++ b/lib/puppet/node/configuration.rb @@ -7,7 +7,7 @@ require 'puppet/external/gratr/digraph' # and the relationships between them. class Puppet::Node::Configuration < Puppet::PGraph extend Puppet::Indirector - indirects :configuration + indirects :configuration, :terminus_class => :code # The host name this is a configuration for. attr_accessor :name diff --git a/lib/puppet/node/facts.rb b/lib/puppet/node/facts.rb index a2e6d9c04..2da6c488e 100755 --- a/lib/puppet/node/facts.rb +++ b/lib/puppet/node/facts.rb @@ -9,7 +9,7 @@ class Puppet::Node::Facts extend Puppet::Indirector # Use the node source as the indirection terminus. - indirects :facts + indirects :facts, :terminus_class => :code attr_accessor :name, :values diff --git a/lib/puppet/parser/compile.rb b/lib/puppet/parser/compile.rb index 6aeebeaae..992b165e5 100644 --- a/lib/puppet/parser/compile.rb +++ b/lib/puppet/parser/compile.rb @@ -16,8 +16,6 @@ class Puppet::Parser::Compile include Puppet::Util::Errors attr_reader :topscope, :parser, :node, :facts, :collections, :configuration - attr_writer :ast_nodes - # Add a collection to the global list. def add_collection(coll) @collections << coll @@ -25,7 +23,7 @@ class Puppet::Parser::Compile # Do we use nodes found in the code, vs. the external node sources? def ast_nodes? - defined?(@ast_nodes) and @ast_nodes + parser.nodes.length > 0 end # Store the fact that we've evaluated a class, and store a reference to diff --git a/lib/puppet/parser/interpreter.rb b/lib/puppet/parser/interpreter.rb index 0b8c035ba..8c727118c 100644 --- a/lib/puppet/parser/interpreter.rb +++ b/lib/puppet/parser/interpreter.rb @@ -26,7 +26,7 @@ class Puppet::Parser::Interpreter # evaluate our whole tree def compile(node) raise Puppet::ParseError, "Could not parse configuration; cannot compile" unless env_parser = parser(node.environment) - return Puppet::Parser::Compile.new(node, env_parser, :ast_nodes => usenodes?).compile + return Puppet::Parser::Compile.new(node, env_parser).compile end # create our interpreter @@ -53,11 +53,6 @@ class Puppet::Parser::Interpreter @parsers = {} end - # Should we parse ast nodes? - def usenodes? - defined?(@usenodes) and @usenodes - end - private # Create a new parser object and pre-parse the configuration. diff --git a/spec/unit/indirector/code/configuration.rb b/spec/unit/indirector/code/configuration.rb index 8652f342d..5e2aedc7b 100755 --- a/spec/unit/indirector/code/configuration.rb +++ b/spec/unit/indirector/code/configuration.rb @@ -39,6 +39,11 @@ describe Puppet::Indirector::Code::Configuration do compiler.find('node1') compiler.find('node2') end + + it "should provide a method for determining if the configuration is networked" do + compiler = Puppet::Indirector::Code::Configuration.new + compiler.should respond_to(:networked?) + end end describe Puppet::Indirector::Code::Configuration, " when creating the interpreter" do @@ -70,7 +75,6 @@ describe Puppet::Indirector::Code::Configuration, " when creating the interprete Puppet::Parser::Interpreter.expects(:new).with(:Code => code).returns(interp) @compiler.send(:interpreter).should equal(interp) end - end describe Puppet::Indirector::Code::Configuration, " when finding nodes" do @@ -132,10 +136,17 @@ describe Puppet::Indirector::Code::Configuration, " when creating configurations before do @compiler = Puppet::Indirector::Code::Configuration.new @name = "me" - @node = stub 'node', :merge => nil, :name => @name, :environment => "yay" + @node = Puppet::Node.new @name, :environment => "yay" + @node.stubs(:merge) Puppet::Node.stubs(:search).with(@name).returns(@node) end + it "should directly use provided nodes" do + Puppet::Node.expects(:search).never + @compiler.interpreter.expects(:compile).with(@node) + @compiler.find(@node) + end + it "should pass the found node to the interpreter for compiling" do config = mock 'config' @compiler.interpreter.expects(:compile).with(@node) @@ -149,6 +160,7 @@ describe Puppet::Indirector::Code::Configuration, " when creating configurations end it "should benchmark the compile process" do + @compiler.stubs(:networked?).returns(true) @compiler.expects(:benchmark).with do |level, message| level == :notice and message =~ /^Compiled configuration/ end diff --git a/spec/unit/indirector/indirector.rb b/spec/unit/indirector/indirector.rb index 5c3ddf9d3..390907ca2 100755 --- a/spec/unit/indirector/indirector.rb +++ b/spec/unit/indirector/indirector.rb @@ -44,6 +44,13 @@ describe Puppet::Indirector, "when registering an indirection" do @thingie.indirection.should equal(@indirection) end + it "should allow specification of a default terminus" do + klass = mock 'terminus class' + Puppet::Indirector::Terminus.stubs(:terminus_class).with(:foo, :first).returns(klass) + @indirection = @thingie.indirects :first, :terminus_class => :foo + @indirection.terminus_class.should == :foo + end + after do @indirection.delete if @indirection end diff --git a/spec/unit/node/configuration.rb b/spec/unit/node/configuration.rb index 6b0677973..c94f31380 100755 --- a/spec/unit/node/configuration.rb +++ b/spec/unit/node/configuration.rb @@ -490,3 +490,27 @@ describe Puppet::Node::Configuration, " when writing dot files" do Puppet.settings.clear end end + +describe Puppet::Node::Configuration, " when indirecting" do + before do + @indirection = mock 'indirection' + + Puppet::Indirector::Indirection.clear_cache + @configuration = Puppet::Node::Facts.new("me") + end + + it "should redirect to the indirection for retrieval" do + Puppet::Node::Configuration.stubs(:indirection).returns(@indirection) + @indirection.expects(:find).with(:myconfig) + Puppet::Node::Configuration.find(:myconfig) + end + + it "should default to the code terminus" do + Puppet::Node::Configuration.indirection.terminus_class.should == :code + end + + after do + mocha_verify + Puppet::Indirector::Indirection.clear_cache + end +end diff --git a/spec/unit/node/facts.rb b/spec/unit/node/facts.rb index 61f05a2b2..ef5c91071 100755 --- a/spec/unit/node/facts.rb +++ b/spec/unit/node/facts.rb @@ -6,25 +6,30 @@ require 'puppet/node/facts' describe Puppet::Node::Facts, " when indirecting" do before do - @terminus = mock 'terminus' - Puppet::Node::Facts.stubs(:indirection).returns(@terminus) + @indirection = mock 'indirection' - # We have to clear the cache so that the facts ask for our terminus stub, + # We have to clear the cache so that the facts ask for our indirection stub, # instead of anything that might be cached. Puppet::Indirector::Indirection.clear_cache @facts = Puppet::Node::Facts.new("me", "one" => "two") end it "should redirect to the specified fact store for retrieval" do - @terminus.expects(:find).with(:my_facts) + Puppet::Node::Facts.stubs(:indirection).returns(@indirection) + @indirection.expects(:find).with(:my_facts) Puppet::Node::Facts.find(:my_facts) end it "should redirect to the specified fact store for storage" do - @terminus.expects(:save).with(@facts) + Puppet::Node::Facts.stubs(:indirection).returns(@indirection) + @indirection.expects(:save).with(@facts) @facts.save end + it "should default to the code terminus" do + Puppet::Node::Facts.indirection.terminus_class.should == :code + end + after do mocha_verify Puppet::Indirector::Indirection.clear_cache diff --git a/spec/unit/parser/compile.rb b/spec/unit/parser/compile.rb index f6b3c9b3f..8bfcdd495 100755 --- a/spec/unit/parser/compile.rb +++ b/spec/unit/parser/compile.rb @@ -49,4 +49,14 @@ describe Puppet::Parser::Compile, " when compiling" do @compile.resources.find { |r| r.to_s == "Class[two]" }.should be_nil @compile.resources.find { |r| r.to_s == "Class[four]" }.should be_nil end + + it "should enable ast_nodes if the parser has any nodes" do + @parser.expects(:nodes).returns(:one => :yay) + @compile.ast_nodes?.should be_true + end + + it "should disable ast_nodes if the parser has no nodes" do + @parser.expects(:nodes).returns({}) + @compile.ast_nodes?.should be_false + end end diff --git a/spec/unit/parser/interpreter.rb b/spec/unit/parser/interpreter.rb index b4aa2a2d1..fbf3bdb23 100755 --- a/spec/unit/parser/interpreter.rb +++ b/spec/unit/parser/interpreter.rb @@ -24,16 +24,6 @@ describe Puppet::Parser::Interpreter, " when initializing" do interp.code.should equal(:code) interp.file.should be_nil end - - it "should default to usenodes" do - interp = Puppet::Parser::Interpreter.new - interp.usenodes?.should be_true - end - - it "should allow disabling of usenodes" do - interp = Puppet::Parser::Interpreter.new :UseNodes => false - interp.usenodes?.should be_false - end end describe Puppet::Parser::Interpreter, " when creating parser instances" do @@ -159,22 +149,13 @@ describe Puppet::Parser::Interpreter, " when compiling configurations" do @parser = mock 'parser' end - it "should create a compile with the node, parser, and whether to use ast nodes when ast nodes is true" do + it "should create a compile with the node and parser" do @compile.expects(:compile).returns(:config) @interp.expects(:parser).with(:myenv).returns(@parser) - @interp.expects(:usenodes?).returns(true) - Puppet::Parser::Compile.expects(:new).with(@node, @parser, :ast_nodes => true).returns(@compile) + Puppet::Parser::Compile.expects(:new).with(@node, @parser).returns(@compile) @interp.compile(@node) end - it "should create a compile with the node, parser, and whether to use ast nodes when ast nodes is false" do - @compile.expects(:compile).returns(:config) - @interp.expects(:parser).with(:myenv).returns(@parser) - @interp.expects(:usenodes?).returns(false) - Puppet::Parser::Compile.expects(:new).with(@node, @parser, :ast_nodes => false).returns(@compile) - @interp.compile(@node).should equal(:config) - end - it "should fail intelligently when no parser can be found" do @interp.expects(:parser).with(:myenv).returns(nil) proc { @interp.compile(@node) }.should raise_error(Puppet::ParseError) diff --git a/test/language/compile.rb b/test/language/compile.rb index 5732acba3..7a8a613af 100755 --- a/test/language/compile.rb +++ b/test/language/compile.rb @@ -23,7 +23,7 @@ class TestCompile < Test::Unit::TestCase def mkparser # This should mock an interpreter - @parser = stub 'parser', :version => "1.0" + @parser = stub 'parser', :version => "1.0", :nodes => {} end def mkcompile(options = {}) @@ -38,7 +38,7 @@ class TestCompile < Test::Unit::TestCase def test_initialize compile = nil node = stub 'node', :name => "foo" - parser = stub 'parser', :version => "1.0" + parser = stub 'parser', :version => "1.0", :nodes => {} assert_nothing_raised("Could not init compile with all required options") do compile = Compile.new(node, parser) end @@ -51,7 +51,7 @@ class TestCompile < Test::Unit::TestCase # Now try it with some options assert_nothing_raised("Could not init compile with extra options") do - compile = Compile.new(node, parser, :ast_nodes => false) + compile = Compile.new(node, parser) end assert_equal(false, compile.ast_nodes?, "Did not set ast_nodes? correctly") @@ -188,7 +188,7 @@ class TestCompile < Test::Unit::TestCase # Make sure we either don't look for nodes, or that we find and evaluate the right object. def test_evaluate_ast_node # First try it with ast_nodes disabled - compile = mkcompile :ast_nodes => false + compile = mkcompile name = compile.node.name compile.expects(:ast_nodes?).returns(false) compile.parser.expects(:nodes).never @@ -201,7 +201,7 @@ class TestCompile < Test::Unit::TestCase # Now try it with them enabled, but no node found. nodes = mock 'node_hash' - compile = mkcompile :ast_nodes => true + compile = mkcompile name = compile.node.name compile.expects(:ast_nodes?).returns(true) compile.parser.stubs(:nodes).returns(nodes) @@ -221,7 +221,7 @@ class TestCompile < Test::Unit::TestCase end # Finally, make sure it works dandily when we have a node - compile = mkcompile :ast_nodes => true + compile = mkcompile compile.expects(:ast_nodes?).returns(true) node = stub 'node', :classname => "c" @@ -240,7 +240,7 @@ class TestCompile < Test::Unit::TestCase "Did not create node resource") # Lastly, check when we actually find the default. - compile = mkcompile :ast_nodes => true + compile = mkcompile compile.expects(:ast_nodes?).returns(true) node = stub 'node', :classname => "default" diff --git a/test/language/snippets.rb b/test/language/snippets.rb index 7168a81d8..cc3859552 100755 --- a/test/language/snippets.rb +++ b/test/language/snippets.rb @@ -449,45 +449,24 @@ class TestSnippets < Test::Unit::TestCase #eval("alias %s %s" % [testname, mname]) testname = ("test_" + mname).intern self.send(:define_method, testname) { + Puppet[:manifest] = snippet(file) facts = { "hostname" => "testhost", "domain" => "domain.com", "ipaddress" => "127.0.0.1", "fqdn" => "testhost.domain.com" } - Facter.stubs(:each) - facts.each do |name, value| - Facter.stubs(:value).with(name).returns(value) - end - # first parse the file - server = Puppet::Network::Handler.master.new( - :Manifest => snippet(file), - :Local => true - ) - facts = Puppet::Node::Facts.new("testhost", facts) - Puppet::Node::Facts.stubs(:save) - Puppet::Node::Facts.stubs(:find).returns(facts) - client = Puppet::Network::Client.master.new( - :Master => server, - :Cache => false - ) - client.class.stubs(:facts).returns(facts.values) - - assert(client.local) - assert_nothing_raised { - client.getconfig() - } - client = Puppet::Network::Client.master.new( - :Master => server, - :Cache => false - ) + node = Puppet::Node.new("testhost") + node.merge(facts) - assert(client.local) - # Now do it again - Puppet::Type.allclear - assert_nothing_raised { - client.getconfig() + config = nil + assert_nothing_raised("Could not compile configuration") { + config = Puppet::Node::Configuration.find(node) + } + + assert_nothing_raised("Could not convert configuration") { + config = config.extract_to_transportable.to_configuration } Puppet::Type.eachtype { |type| @@ -500,12 +479,10 @@ class TestSnippets < Test::Unit::TestCase assert(obj.name) } } - @configuration = client.configuration + @configuration = config assert_nothing_raised { self.send(mname) } - - client.clear } mname = mname.intern end diff --git a/test/rails/configuration.rb b/test/rails/configuration.rb index 752ea5375..07665d576 100755 --- a/test/rails/configuration.rb +++ b/test/rails/configuration.rb @@ -25,7 +25,6 @@ class ConfigurationRailsTests < PuppetTest::TestCase def test_finish_before_store railsinit compile = mkcompile - compile.ast_nodes = true parser = compile.parser node = parser.newnode [compile.node.name], :code => AST::ASTArray.new(:children => [ |