summaryrefslogtreecommitdiffstats
path: root/spec/integration/parser
diff options
context:
space:
mode:
authorDominic Cleal <dcleal@redhat.com>2010-11-27 13:36:04 +0000
committerDominic Cleal <dcleal@redhat.com>2010-11-27 13:36:04 +0000
commitafe2d014feb2210a8666c93465d11e9c9d555f8b (patch)
tree208f5ac82b2c29610d2021821c8fca9b079e638b /spec/integration/parser
parent143fc744a839affd328234fca26246d49d15d3d8 (diff)
parent4b35402ba85d8842d757becec5c8a7bf4d6f6654 (diff)
Merge branch 'master' of github.com:domcleal/puppet into master-old
Diffstat (limited to 'spec/integration/parser')
-rwxr-xr-xspec/integration/parser/collector_spec.rb2
-rwxr-xr-xspec/integration/parser/compiler_spec.rb105
-rw-r--r--spec/integration/parser/functions_spec.rb21
-rwxr-xr-xspec/integration/parser/parser_spec.rb8
-rw-r--r--spec/integration/parser/ruby_manifest_spec.rb128
5 files changed, 260 insertions, 4 deletions
diff --git a/spec/integration/parser/collector_spec.rb b/spec/integration/parser/collector_spec.rb
index 73273c909..b1cfc51c7 100755
--- a/spec/integration/parser/collector_spec.rb
+++ b/spec/integration/parser/collector_spec.rb
@@ -17,7 +17,7 @@ describe Puppet::Parser::Collector do
def query(text)
code = "File <| #{text} |>"
parser = Puppet::Parser::Parser.new(@scope.compiler)
- parser.parse(code).hostclass("").code[0].query
+ return parser.parse(code).code[0].query
end
{true => [%{title == "/tmp/testing"}, %{(title == "/tmp/testing")}, %{group == bin},
diff --git a/spec/integration/parser/compiler_spec.rb b/spec/integration/parser/compiler_spec.rb
index 83bbf9500..f731692b3 100755
--- a/spec/integration/parser/compiler_spec.rb
+++ b/spec/integration/parser/compiler_spec.rb
@@ -26,4 +26,109 @@ describe Puppet::Parser::Compiler do
@compiler.catalog.version.should == version
end
+
+ it "should not create duplicate resources when a class is referenced both directly and indirectly by the node classifier (4792)" do
+ Puppet[:code] = <<-PP
+ class foo
+ {
+ notify { foo_notify: }
+ include bar
+ }
+ class bar
+ {
+ notify { bar_notify: }
+ }
+ PP
+
+ @node.stubs(:classes).returns(['foo', 'bar'])
+
+ catalog = Puppet::Parser::Compiler.compile(@node)
+
+ catalog.resource("Notify[foo_notify]").should_not be_nil
+ catalog.resource("Notify[bar_notify]").should_not be_nil
+ end
+
+ describe "when resolving class references" do
+ it "should favor local scope, even if there's an included class in topscope" do
+ Puppet[:code] = <<-PP
+ class experiment {
+ class baz {
+ }
+ notify {"x" : require => Class[Baz] }
+ }
+ class baz {
+ }
+ include baz
+ include experiment
+ include experiment::baz
+ PP
+
+ catalog = Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode"))
+
+ notify_resource = catalog.resource( "Notify[x]" )
+
+ notify_resource[:require].title.should == "Experiment::Baz"
+ end
+
+ it "should favor local scope, even if there's an unincluded class in topscope" do
+ Puppet[:code] = <<-PP
+ class experiment {
+ class baz {
+ }
+ notify {"x" : require => Class[Baz] }
+ }
+ class baz {
+ }
+ include experiment
+ include experiment::baz
+ PP
+
+ catalog = Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode"))
+
+ notify_resource = catalog.resource( "Notify[x]" )
+
+ notify_resource[:require].title.should == "Experiment::Baz"
+ end
+ end
+
+ it "should recompute the version after input files are re-parsed" do
+ Puppet[:code] = 'class foo { }'
+ Time.stubs(:now).returns(1)
+ node = Puppet::Node.new('mynode')
+ Puppet::Parser::Compiler.compile(node).version.should == 1
+ Time.stubs(:now).returns(2)
+ Puppet::Parser::Compiler.compile(node).version.should == 1 # no change because files didn't change
+ Puppet::Resource::TypeCollection.any_instance.stubs(:stale?).returns(true).then.returns(false) # pretend change
+ Puppet::Parser::Compiler.compile(node).version.should == 2
+ end
+
+ ['class', 'define', 'node'].each do |thing|
+ it "should not allow #{thing} inside evaluated conditional constructs" do
+ Puppet[:code] = <<-PP
+ if true {
+ #{thing} foo {
+ }
+ notify { decoy: }
+ }
+ PP
+
+ begin
+ Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode"))
+ raise "compilation should have raised Puppet::Error"
+ rescue Puppet::Error => e
+ e.message.should =~ /at line 2/
+ end
+ end
+ end
+
+ it "should not allow classes inside unevaluated conditional constructs" do
+ Puppet[:code] = <<-PP
+ if false {
+ class foo {
+ }
+ }
+ PP
+
+ lambda { Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode")) }.should raise_error(Puppet::Error)
+ end
end
diff --git a/spec/integration/parser/functions_spec.rb b/spec/integration/parser/functions_spec.rb
new file mode 100644
index 000000000..cbfb4ac88
--- /dev/null
+++ b/spec/integration/parser/functions_spec.rb
@@ -0,0 +1,21 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+describe Puppet::Parser::Functions do
+ before :each do
+ Puppet::Parser::Functions.rmfunction("template") if Puppet::Parser::Functions.function("template")
+ end
+
+ it "should support multiple threads autoloading the same function" do
+ threads = []
+ lambda {
+ 10.times { |a|
+ threads << Thread.new {
+ Puppet::Parser::Functions.function("template")
+ }
+ }
+ }.should_not raise_error
+ threads.each { |t| t.join }
+ end
+end \ No newline at end of file
diff --git a/spec/integration/parser/parser_spec.rb b/spec/integration/parser/parser_spec.rb
index 7b85bcacb..0d9aa51e1 100755
--- a/spec/integration/parser/parser_spec.rb
+++ b/spec/integration/parser/parser_spec.rb
@@ -11,7 +11,7 @@ describe Puppet::Parser::Parser do
end
def result_instance
- @result.hostclass("").code[0]
+ @result.code[0]
end
def matches?(string)
@@ -44,7 +44,7 @@ describe Puppet::Parser::Parser do
end
def result_instance
- @result.hostclass("").code[0]
+ @result.code[0]
end
def matches?(string)
@@ -85,7 +85,9 @@ describe Puppet::Parser::Parser do
class test {}
""")
- ast.hostclass("test").doc.should == "comment\n"
+ ast.code[0].should be_a(Puppet::Parser::AST::Hostclass)
+ ast.code[0].name.should == 'test'
+ ast.code[0].instantiate('')[0].doc.should == "comment\n"
end
end
diff --git a/spec/integration/parser/ruby_manifest_spec.rb b/spec/integration/parser/ruby_manifest_spec.rb
new file mode 100644
index 000000000..de6f4628c
--- /dev/null
+++ b/spec/integration/parser/ruby_manifest_spec.rb
@@ -0,0 +1,128 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'tempfile'
+require 'puppet_spec/files'
+
+describe "Pure ruby manifests" do
+ include PuppetSpec::Files
+
+ before do
+ @node = Puppet::Node.new "testnode"
+
+ @scope_resource = stub 'scope_resource', :builtin? => true, :finish => nil, :ref => 'Class[main]'
+ @scope = stub 'scope', :resource => @scope_resource, :source => mock("source")
+ @test_dir = tmpdir('ruby_manifest_test')
+ end
+
+ after do
+ Puppet.settings.clear
+ end
+
+ def write_file(name, contents)
+ path = File.join(@test_dir, name)
+ File.open(path, "w") { |f| f.write(contents) }
+ path
+ end
+
+ def compile(contents)
+ Puppet[:code] = contents
+ Dir.chdir(@test_dir) do
+ Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode"))
+ end
+ end
+
+ it "should allow classes" do
+ write_file('foo.rb', ["hostclass 'one' do notify('one_notify') end",
+ "hostclass 'two' do notify('two_notify') end"].join("\n"))
+ catalog = compile("import 'foo'\ninclude one")
+ catalog.resource("Notify[one_notify]").should_not be_nil
+ catalog.resource("Notify[two_notify]").should be_nil
+ end
+
+ it "should allow defines" do
+ write_file('foo.rb', 'define "bar", :arg do notify("bar_#{@name}_#{@arg}") end')
+ catalog = compile("import 'foo'\nbar { instance: arg => 'xyz' }")
+ catalog.resource("Notify[bar_instance_xyz]").should_not be_nil
+ catalog.resource("Bar[instance]").should_not be_nil
+ end
+
+ it "should allow node declarations" do
+ write_file('foo.rb', "node 'mynode' do notify('mynode') end")
+ catalog = compile("import 'foo'")
+ node_declaration = catalog.resource("Notify[mynode]")
+ node_declaration.should_not be_nil
+ node_declaration.title.should == 'mynode'
+ end
+
+ it "should allow access to the environment" do
+ write_file('foo.rb', ["hostclass 'bar' do",
+ " if environment.is_a? Puppet::Node::Environment",
+ " notify('success')",
+ " end",
+ "end"].join("\n"))
+ compile("import 'foo'\ninclude bar").resource("Notify[success]").should_not be_nil
+ end
+
+ it "should allow creation of resources of built-in types" do
+ write_file('foo.rb', "hostclass 'bar' do file 'test_file', :owner => 'root', :mode => '644' end")
+ catalog = compile("import 'foo'\ninclude bar")
+ file = catalog.resource("File[test_file]")
+ file.should be_a(Puppet::Resource)
+ file.type.should == 'File'
+ file.title.should == 'test_file'
+ file.exported.should_not be
+ file.virtual.should_not be
+ file[:owner].should == 'root'
+ file[:mode].should == '644'
+ file[:stage].should be_nil # TODO: is this correct behavior?
+ end
+
+ it "should allow calling user-defined functions" do
+ write_file('foo.rb', "hostclass 'bar' do user_func 'name', :arg => 'xyz' end")
+ catalog = compile(['define user_func($arg) { notify {"n_$arg": } }',
+ 'import "foo"',
+ 'include bar'].join("\n"))
+ catalog.resource("Notify[n_xyz]").should_not be_nil
+ catalog.resource("User_func[name]").should_not be_nil
+ end
+
+ it "should be properly cached for multiple compiles" do
+ # Note: we can't test this by calling compile() twice, because
+ # that sets Puppet[:code], which clears out all cached
+ # environments.
+ Puppet[:filetimeout] = 1000
+ write_file('foo.rb', "hostclass 'bar' do notify('success') end")
+ Puppet[:code] = "import 'foo'\ninclude bar"
+
+ # Compile the catalog and check it
+ catalog = Dir.chdir(@test_dir) do
+ Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode"))
+ end
+ catalog.resource("Notify[success]").should_not be_nil
+
+ # Secretly change the file to make it invalid. This change
+ # shouldn't be noticed because the we've set a high
+ # Puppet[:filetimeout].
+ write_file('foo.rb', "raise 'should not be executed'")
+
+ # Compile the catalog a second time and make sure it's still ok.
+ catalog = Dir.chdir(@test_dir) do
+ Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode"))
+ end
+ catalog.resource("Notify[success]").should_not be_nil
+ end
+
+ it "should be properly reloaded when stale" do
+ Puppet[:filetimeout] = -1 # force stale check to happen all the time
+ write_file('foo.rb', "hostclass 'bar' do notify('version1') end")
+ catalog = compile("import 'foo'\ninclude bar")
+ catalog.resource("Notify[version1]").should_not be_nil
+ sleep 1 # so that timestamp will change forcing file reload
+ write_file('foo.rb', "hostclass 'bar' do notify('version2') end")
+ catalog = compile("import 'foo'\ninclude bar")
+ catalog.resource("Notify[version1]").should be_nil
+ catalog.resource("Notify[version2]").should_not be_nil
+ end
+end