Project

General

Profile

« Previous | Next » 

Revision af58b9f1

Added by Rickard von Essen over 10 years ago

fixes #2878 - Import Classes when using parser = future, on Puppet 3.2+

View differences:

lib/proxy/puppet/class_scanner.rb
require 'proxy/puppet/puppet_class'
module Proxy::Puppet
class ClassScanner
class << self
# scans a given directory and its sub directory for puppet classes
# returns an array of PuppetClass objects.
def scan_directory directory
parser = Puppet::Parser::Parser.new Puppet::Node::Environment.new
Dir.glob("#{directory}/*/manifests/**/*.pp").map do |filename|
scan_manifest File.read(filename), parser, filename
end.compact.flatten
end
def scan_manifest manifest, parser, filename = ''
klasses = []
already_seen = Set.new parser.known_resource_types.hostclasses.keys
already_seen << '' # Prevent the toplevel "main" class from matching
ast = parser.parse manifest
# Get the parsed representation of the top most objects
hostclasses = ast.respond_to?(:instantiate) ? ast.instantiate('') : ast.hostclasses.values
hostclasses.each do |klass|
# Only look at classes
if klass.type == :hostclass and not already_seen.include? klass.namespace
params = {}
# Get parameters and eventual default values
klass.arguments.each do |name, value|
params[name] = ast_to_value(value) rescue nil
end
klasses << PuppetClass.new(klass.namespace, params)
end
end
klasses
rescue => e
puts "Error while parsing #{filename}: #{e}"
klasses
end
def ast_to_value value
unless value.class.name.start_with? "Puppet::Parser::AST::"
# Native Ruby types
case value
# Supported with exact JSON equivalent
when NilClass, String, Numeric, Array, Hash, FalseClass, TrueClass
value
when Struct
value.hash
when Enumerable
value.to_a
# Stringified
when Regexp # /(?:stringified)/
"/#{value.to_s}/"
when Symbol # stringified
value.to_s
else
raise TypeError
end
else
# Parser types
case value
# Supported with exact JSON equivalent
when Puppet::Parser::AST::Boolean, Puppet::Parser::AST::String
value.evaluate nil
# Supported with stringification
when Puppet::Parser::AST::Concat
# This is the case when two params are concatenated together ,e.g. "param_${key}_something"
# Note1: only simple content are supported, plus variables whose raw name is taken
# Note2: The variable substitution WON'T be done by Puppet from the ENC YAML output
value.value.map do |v|
case v
when Puppet::Parser::AST::String
v.evaluate nil
when Puppet::Parser::AST::Variable
"${#{v.value}}"
else
raise TypeError
end
end.join rescue nil
when Puppet::Parser::AST::Variable
"${#{value}}"
when Puppet::Parser::AST::Type
value.value
when Puppet::Parser::AST::Name
(Puppet::Parser::Scope.number?(value.value) or value.value)
when Puppet::Parser::AST::Undef # equivalent of nil, but optional
""
# Depends on content
when Puppet::Parser::AST::ASTArray
value.inject([]) { |arr, v| (arr << ast_to_value(v)) rescue arr }
when Puppet::Parser::AST::ASTHash
Hash[value.value.each.inject([]) { |arr, (k,v)| (arr << [ast_to_value(k), ast_to_value(v)]) rescue arr }]
when Puppet::Parser::AST::Function
value.to_s
# Let's see if a raw evaluation works with no scope for any other type
else
if value.respond_to? :evaluate
# Can probably work for: (depending on the actual content)
# - Puppet::Parser::AST::ArithmeticOperator
# - Puppet::Parser::AST::ComparisonOperator
# - Puppet::Parser::AST::BooleanOperator
# - Puppet::Parser::AST::Minus
# - Puppet::Parser::AST::Not
# May work for:
# - Puppet::Parser::AST::InOperator
# - Puppet::Parser::AST::MatchOperator
# - Puppet::Parser::AST::Selector
# Probably won't work for
# - Puppet::Parser::AST::Variable
# - Puppet::Parser::AST::HashOrArrayAccess
# - Puppet::Parser::AST::ResourceReference
value.evaluate nil
else
raise TypeError
end
end
end
end
end
end
end
lib/proxy/puppet/class_scanner_eparser.rb
require 'proxy/puppet/puppet_class'
if Puppet::PUPPETVERSION.to_f >= 3.2
require 'puppet/pops'
module Proxy::Puppet
class ClassScannerEParser
class << self
# scans a given directory and its sub directory for puppet classes
# returns an array of PuppetClass objects.
def scan_directory directory
parser = Puppet::Pops::Parser::Parser.new
Dir.glob("#{directory}/*/manifests/**/*.pp").map do |filename|
scan_manifest File.read(filename), parser, filename
end.compact.flatten
end
def scan_manifest manifest, parser, filename = ''
klasses = []
already_seen = Set.new
already_seen << '' # Prevent the toplevel "main" class from matching
ast = parser.parse_string manifest
class_finder = ClassFinder.new
class_finder.do_find ast.current
klasses = class_finder.klasses
klasses
rescue => e
puts "Error while parsing #{filename}: #{e}"
klasses
end
end
end
class ClassFinder
@@finder_visitor ||= Puppet::Pops::Visitor.new(nil,'find',0,0)
attr_reader :klasses
def initialize
@klasses = []
end
def do_find ast
@@finder_visitor.visit_this(self, ast)
end
def find_HostClassDefinition o
params = {}
o.parameters.each do |param|
params[param.name] = ast_to_value_new(param.value) rescue nil
end
@klasses << PuppetClass.new(o.name, params)
if o.body
do_find(o.body)
end
end
def find_BlockExpression o
o.statements.collect {|x| do_find(x) }
end
def find_CallNamedFunctionExpression o
if o.lambda
do_find(o.lambda)
end
end
def find_Object o
#puts "Unhandled object:#{o}"
end
def ast_to_value_new value
unless value.class.name.start_with? "Puppet::Pops::Model::"
# Native Ruby types
case value
# Supported with exact JSON equivalent
when NilClass, String, Numeric, Array, Hash, FalseClass, TrueClass
value
when Struct
value.hash
when Enumerable
value.to_a
# Stringified
when Regexp # /(?:stringified)/
"/#{value.to_s}/"
when Symbol # stringified
value.to_s
else
raise TypeError
end
else
# Parser types
case value
# Supported with exact JSON equivalent
when Puppet::Pops::Model::BooleanExpression, Puppet::Pops::Model::LiteralString, Puppet::Pops::Model::LiteralNumber, Puppet::Pops::Model::QualifiedName
(Puppet::Parser::Scope.number?(value.value) or value.value)
when Puppet::Pops::Model::UnaryMinusExpression
- ast_to_value_new(value.expr)
when Puppet::Pops::Model::ArithmeticExpression
ast_to_value_new(value.left_expr).send(value.operator, ast_to_value_new(value.right_expr))
# Supported with stringification
when Puppet::Pops::Model::ConcatenatedString
# This is the case when two params are concatenated together ,e.g. "param_${key}_something"
# Note1: only simple content are supported, plus variables whose raw name is taken
# Note2: The variable substitution WON'T be done by Puppet from the ENC YAML output
value.segments.map {|v| ast_to_value_new v}.join rescue nil
when Puppet::Pops::Model::TextExpression
ast_to_value_new value.expr
when Puppet::Pops::Model::VariableExpression
"${#{ast_to_value_new value.expr}}"
when Puppet::Pops::Model::TypeReference
value.value
when Puppet::Pops::Model::LiteralUndef
""
# Depends on content
when Puppet::Pops::Model::LiteralList
value.values.inject([]) { |arr, v| (arr << ast_to_value_new(v)) rescue arr }
when Puppet::Pops::Model::LiteralHash
# Note that all keys are string in Puppet
Hash[value.entries.inject([]) { |arr, entry| (arr << [ast_to_value_new(entry.key).to_s, ast_to_value_new(entry.value)]) rescue arr }]
when Puppet::Pops::Model::NamedFunctionDefinition
value.to_s
# Let's see if a raw evaluation works with no scope for any other type
else
if value.respond_to? :value
value.value
elsif value.respond_to? :expr
ast_to_value_new value.expr
else
raise TypeError
end
end
end
end
end
end
end
lib/proxy/puppet/environment.rb
end
def classes
paths.map {|path| PuppetClass.scan_directory path}.flatten
conf = Puppet.settings.instance_variable_get(:@values)
eparser = conf[:master] && conf[:master][:parser] == 'future'
paths.map {|path| PuppetClass.scan_directory path, eparser}.flatten
end
end
lib/proxy/puppet/puppet_class.rb
require 'proxy/puppet/initializer'
require 'proxy/puppet/class_scanner'
require 'proxy/puppet/class_scanner_eparser'
module Proxy::Puppet
......
class << self
# scans a given directory and its sub directory for puppet classes
# returns an array of PuppetClass objects.
def scan_directory directory
def scan_directory directory, eparser = false
# Get a Puppet Parser to parse the manifest source
Initializer.load
parser = Puppet::Parser::Parser.new Puppet::Node::Environment.new
Dir.glob("#{directory}/*/manifests/**/*.pp").map do |filename|
scan_manifest File.read(filename), filename, parser
end.compact.flatten
end
def scan_manifest manifest, filename = '', parser = nil
klasses = []
# Get a Puppet Parser to parse the manifest source
unless parser
Initializer.load
parser = Puppet::Parser::Parser.new(Puppet::Node::Environment.new)
end
already_seen = Set.new parser.known_resource_types.hostclasses.keys
already_seen << '' # Prevent the toplevel "main" class from matching
ast = parser.parse manifest
# Get the parsed representation of the top most objects
hostclasses = ast.respond_to?(:instantiate) ? ast.instantiate('') : ast.hostclasses.values
hostclasses.each do |klass|
# Only look at classes
if klass.type == :hostclass and not already_seen.include? klass.namespace
params = {}
# Get parameters and eventual default values
klass.arguments.each do |name, value|
params[name] = ast_to_value(value) rescue nil
end
klasses << new(klass.namespace, params)
end
end
klasses
rescue => e
puts "Error while parsing #{filename}: #{e}"
klasses
end
private
def ast_to_value value
unless value.class.name.start_with? "Puppet::Parser::AST::"
# Native Ruby types
case value
# Supported with exact JSON equivalent
when NilClass, String, Numeric, Array, Hash, FalseClass, TrueClass
value
when Struct
value.hash
when Enumerable
value.to_a
# Stringified
when Regexp # /(?:stringified)/
"/#{value.to_s}/"
when Symbol # stringified
value.to_s
else
raise TypeError
end
if eparser
ClassScannerEParser.scan_directory directory
else
# Parser types
case value
# Supported with exact JSON equivalent
when Puppet::Parser::AST::Boolean, Puppet::Parser::AST::String
value.evaluate nil
# Supported with stringification
when Puppet::Parser::AST::Concat
# This is the case when two params are concatenated together ,e.g. "param_${key}_something"
# Note1: only simple content are supported, plus variables whose raw name is taken
# Note2: The variable substitution WON'T be done by Puppet from the ENC YAML output
value.value.map do |v|
case v
when Puppet::Parser::AST::String
v.evaluate nil
when Puppet::Parser::AST::Variable
"${#{v.value}}"
else
raise TypeError
end
end.join rescue nil
when Puppet::Parser::AST::Variable
"${#{value}}"
when Puppet::Parser::AST::Type
value.value
when Puppet::Parser::AST::Name
(Puppet::Parser::Scope.number?(value.value) or value.value)
when Puppet::Parser::AST::Undef # equivalent of nil, but optional
""
# Depends on content
when Puppet::Parser::AST::ASTArray
value.inject([]) { |arr, v| (arr << ast_to_value(v)) rescue arr }
when Puppet::Parser::AST::ASTHash
Hash[value.value.each.inject([]) { |arr, (k,v)| (arr << [ast_to_value(k), ast_to_value(v)]) rescue arr }]
when Puppet::Parser::AST::Function
value.to_s
# Let's see if a raw evaluation works with no scope for any other type
else
if value.respond_to? :evaluate
# Can probably work for: (depending on the actual content)
# - Puppet::Parser::AST::ArithmeticOperator
# - Puppet::Parser::AST::ComparisonOperator
# - Puppet::Parser::AST::BooleanOperator
# - Puppet::Parser::AST::Minus
# - Puppet::Parser::AST::Not
# May work for:
# - Puppet::Parser::AST::InOperator
# - Puppet::Parser::AST::MatchOperator
# - Puppet::Parser::AST::Selector
# Probably won't work for
# - Puppet::Parser::AST::Variable
# - Puppet::Parser::AST::HashOrArrayAccess
# - Puppet::Parser::AST::ResourceReference
value.evaluate nil
else
raise TypeError
end
end
ClassScanner.scan_directory directory
end
end
end
def initialize name, params = {}
......
end
end
test/class_scanner_eparser_test.rb
require 'test/test_helper'
class ClassScannerEParserTest < Test::Unit::TestCase
def test_should_find_class_in_a_manifest
return unless Puppet::PUPPETVERSION.to_f >= 3.2
manifest = <<-EOF
class foreman::install {
include 'x::y'
}
EOF
require 'puppet/pops'
klasses = Proxy::Puppet::ClassScannerEParser.scan_manifest(manifest, Puppet::Pops::Parser::Parser.new)
assert_kind_of Array, klasses
assert_equal 1, klasses.size
klass = klasses.first
assert_equal "install", klass.name
assert_equal "foreman", klass.module
end
def test_should_not_file_a_class
return unless Puppet::PUPPETVERSION.to_f >= 3.2
manifest = <<-EOF
include 'x::y'
EOF
klasses = Proxy::Puppet::ClassScannerEParser.scan_manifest(manifest, Puppet::Pops::Parser::Parser.new)
assert klasses.empty?
end
def test_should_find_multiple_class_in_a_manifest
return unless Puppet::PUPPETVERSION.to_f >= 3.2
manifest = <<-EOF
class foreman::install {
include 'x::y'
}
class foreman::params {
$var = 'xyz'
}
EOF
klasses = Proxy::Puppet::ClassScannerEParser.scan_manifest(manifest, Puppet::Pops::Parser::Parser.new)
assert_kind_of Array, klasses
assert_equal 2, klasses.size
klasses.sort! { |k1,k2| k1.name <=> k2.name }
klass = klasses.first
assert_equal "install", klass.name
assert_equal "foreman", klass.module
klass = klasses.last
assert_equal "params", klass.name
assert_equal "foreman", klass.module
end
def test_should_scan_a_dir
return unless Puppet::PUPPETVERSION.to_f >= 3.2
klasses = Proxy::Puppet::ClassScannerEParser.scan_directory('/tmp/no_such_dir')
assert_kind_of Array, klasses
assert klasses.empty?
end
def test_should_extract_parameters__no_param_parenthesis
return unless Puppet::PUPPETVERSION.to_f >= 3.2
manifest = <<-EOF
class foreman::install {
}
EOF
klasses = Proxy::Puppet::ClassScannerEParser.scan_manifest(manifest, Puppet::Pops::Parser::Parser.new)
assert_kind_of Array, klasses
assert_equal 1, klasses.size
klass = klasses.first
assert_equal({}, klass.params)
end
def test_should_extract_parameters__empty_param_parenthesis
return unless Puppet::PUPPETVERSION.to_f >= 3.2
manifest = <<-EOF
class foreman::install () {
}
EOF
klasses = Proxy::Puppet::ClassScannerEParser.scan_manifest(manifest, Puppet::Pops::Parser::Parser.new)
assert_kind_of Array, klasses
assert_equal 1, klasses.size
klass = klasses.first
assert_equal({}, klass.params)
end
def test_should_extract_parameters__single_param_no_value
return unless Puppet::PUPPETVERSION.to_f >= 3.2
manifest = <<-EOF
class foreman::install ($mandatory) {
}
EOF
klasses = Proxy::Puppet::ClassScannerEParser.scan_manifest(manifest, Puppet::Pops::Parser::Parser.new)
assert_kind_of Array, klasses
assert_equal 1, klasses.size
klass = klasses.first
assert_equal({'mandatory' => nil}, klass.params)
end
def test_should_extract_parameters__type_coverage
return unless Puppet::PUPPETVERSION.to_f >= 3.2
# Note that all keys are string in Puppet
manifest = <<-EOF
class foreman::install (
$mandatory,
$undef = undef,
$emptyString = '',
$emptyStringDq = "",
$string = "foo",
$integer = 42 + 3,
$float = 3.14,
$str_interpolation = "FLOAT_$float",
$array = ['', "", "foo", -42, 3.14],
$hash = { unquoted => '', "quoted" => "", 42 => "integer", 3.14 => "float", '' => 'empty' },
$complex = { array => ['','foo',42,3.14], hash => {foo=>"bar"}, mixed => [{foo=>bar},{bar=>"baz"}] }
) {
}
EOF
klasses = Proxy::Puppet::ClassScannerEParser.scan_manifest(manifest, Puppet::Pops::Parser::Parser.new)
assert_kind_of Array, klasses
assert_equal 1, klasses.size
klass = klasses.first
assert_equal({
'mandatory' => nil,
'undef' => '',
'emptyString' => '',
'emptyStringDq' => '',
'string' => 'foo',
'integer' => 45,
'float' => 3.14,
'str_interpolation' => 'FLOAT_${float}',
'array' => ['', '', 'foo', -42, 3.14],
# All keys must be strings
'hash' => { 'unquoted' => '', 'quoted' => '', '42' => 'integer', '3.14' => 'float', '' => 'empty' },
'complex' => { 'array' => ['','foo',42,3.14], 'hash' => {'foo'=>'bar'}, 'mixed' => [{'foo'=>'bar'},{'bar'=>'baz'}] }
}, klass.params)
end
def test_should_handle_import_in_a_manifest
return unless Puppet::PUPPETVERSION.to_f >= 3.2
klasses = Proxy::Puppet::ClassScannerEParser.scan_directory('./test/fixtures/modules_include')
assert_kind_of Array, klasses
assert_equal 2, klasses.size
klass = klasses.find {|k| k.name == "sub::foo" }
assert klass
assert_equal "testinclude", klass.module
klass = klasses.find {|k| k.name == "testinclude" }
assert klass
end
#TODO add scans to a real puppet directory with modules
end
test/class_scanner_test.rb
require 'test/test_helper'
class ClassScannerTest < Test::Unit::TestCase
def setup
Proxy::Puppet::Initializer.load
@parser = Puppet::Parser::Parser.new Puppet::Node::Environment.new
end
def test_should_find_class_in_a_manifest
manifest = <<-EOF
class foreman::install {
include 'x::y'
}
EOF
klasses = Proxy::Puppet::ClassScanner.scan_manifest(manifest, @parser)
assert_kind_of Array, klasses
assert_equal 1, klasses.size
klass = klasses.first
assert_equal "install", klass.name
assert_equal "foreman", klass.module
end
def test_should_not_file_a_class
manifest = <<-EOF
include 'x::y'
EOF
klasses = Proxy::Puppet::ClassScanner.scan_manifest(manifest, @parser)
assert klasses.empty?
end
def test_should_find_multiple_class_in_a_manifest
manifest = <<-EOF
class foreman::install {
include 'x::y'
}
class foreman::params {
$var = 'xyz'
}
EOF
klasses = Proxy::Puppet::ClassScanner.scan_manifest(manifest, @parser)
assert_kind_of Array, klasses
assert_equal 2, klasses.size
klasses.sort! { |k1,k2| k1.name <=> k2.name }
klass = klasses.first
assert_equal "install", klass.name
assert_equal "foreman", klass.module
klass = klasses.last
assert_equal "params", klass.name
assert_equal "foreman", klass.module
end
def test_should_scan_a_dir
klasses = Proxy::Puppet::ClassScanner.scan_directory('/tmp/no_such_dir')
assert_kind_of Array, klasses
assert klasses.empty?
end
def test_should_extract_parameters__no_param_parenthesis
manifest = <<-EOF
class foreman::install {
}
EOF
klasses = Proxy::Puppet::ClassScanner.scan_manifest(manifest, @parser)
assert_kind_of Array, klasses
assert_equal 1, klasses.size
klass = klasses.first
assert_equal({}, klass.params)
end
def test_should_extract_parameters__empty_param_parenthesis
manifest = <<-EOF
class foreman::install () {
}
EOF
klasses = Proxy::Puppet::ClassScanner.scan_manifest(manifest, @parser)
assert_kind_of Array, klasses
assert_equal 1, klasses.size
klass = klasses.first
assert_equal({}, klass.params)
end
def test_should_extract_parameters__single_param_no_value
manifest = <<-EOF
class foreman::install ($mandatory) {
}
EOF
klasses = Proxy::Puppet::ClassScanner.scan_manifest(manifest, @parser)
assert_kind_of Array, klasses
assert_equal 1, klasses.size
klass = klasses.first
assert_equal({'mandatory' => nil}, klass.params)
end
def test_should_extract_parameters__type_coverage
# Note that all keys are string in Puppet
manifest = <<-EOF
class foreman::install (
$mandatory,
$undef = undef,
$emptyString = '',
$emptyStringDq = "",
$string = "foo",
$integer = 42,
$float = 3.14,
$array = ['', "", "foo", 42, 3.14],
$hash = { unquoted => '', "quoted" => "", 42 => "integer", 3.14 => "float", '' => 'empty' },
$complex = { array => ['','foo',42,3.14], hash => {foo=>"bar"}, mixed => [{foo=>bar},{bar=>"baz"}] }
) {
}
EOF
klasses = Proxy::Puppet::ClassScanner.scan_manifest(manifest, @parser)
assert_kind_of Array, klasses
assert_equal 1, klasses.size
klass = klasses.first
assert_equal({
'mandatory' => nil,
'undef' => '',
'emptyString' => '',
'emptyStringDq' => '',
'string' => 'foo',
'integer' => 42,
'float' => 3.14,
'array' => ['', '', 'foo', 42, 3.14],
# All keys must be strings
'hash' => { 'unquoted' => '', 'quoted' => '', '42' => 'integer', '3.14' => 'float', '' => 'empty' },
'complex' => { 'array' => ['','foo',42,3.14], 'hash' => {'foo'=>'bar'}, 'mixed' => [{'foo'=>'bar'},{'bar'=>'baz'}] }
}, klass.params)
end
def test_should_handle_import_in_a_manifest
klasses = Proxy::Puppet::ClassScanner.scan_directory('./test/fixtures/modules_include')
assert_kind_of Array, klasses
assert_equal 2, klasses.size
klass = klasses.find {|k| k.name == "sub::foo" }
assert klass
assert_equal "testinclude", klass.module
klass = klasses.find {|k| k.name == "testinclude" }
assert klass
end
#TODO add scans to a real puppet directory with modules
end
test/puppet_class_test.rb
class PuppetClassTest < Test::Unit::TestCase
def setup
Puppet::Node::Environment.clear
end
def test_should_have_a_logger
assert_respond_to Proxy::Puppet, :logger
end
......
klass = Proxy::Puppet::PuppetClass.new "foreman_proxy::install"
assert_kind_of Proxy::Puppet::PuppetClass, klass
end
def test_should_find_class_in_a_manifest
manifest = <<-EOF
class foreman::install {
include 'x::y'
}
EOF
klasses = Proxy::Puppet::PuppetClass.scan_manifest(manifest)
assert_kind_of Array, klasses
assert_equal 1, klasses.size
klass = klasses.first
assert_equal "install", klass.name
assert_equal "foreman", klass.module
end
def test_should_not_file_a_class
manifest = <<-EOF
include 'x::y'
EOF
klasses = Proxy::Puppet::PuppetClass.scan_manifest(manifest)
assert klasses.empty?
end
def test_should_find_multiple_class_in_a_manifest
manifest = <<-EOF
class foreman::install {
include 'x::y'
}
class foreman::params {
$var = 'xyz'
}
EOF
klasses = Proxy::Puppet::PuppetClass.scan_manifest(manifest)
assert_kind_of Array, klasses
assert_equal 2, klasses.size
klasses.sort! { |k1,k2| k1.name <=> k2.name }
klass = klasses.first
assert_equal "install", klass.name
assert_equal "foreman", klass.module
klass = klasses.last
assert_equal "params", klass.name
assert_equal "foreman", klass.module
end
def test_should_scan_a_dir
klasses = Proxy::Puppet::PuppetClass.scan_directory('/tmp/no_such_dir')
assert_kind_of Array, klasses
assert klasses.empty?
end
def test_should_extract_parameters__no_param_parenthesis
manifest = <<-EOF
class foreman::install {
}
EOF
klasses = Proxy::Puppet::PuppetClass.scan_manifest(manifest)
assert_kind_of Array, klasses
assert_equal 1, klasses.size
klass = klasses.first
assert_equal({}, klass.params)
end
def test_should_extract_parameters__empty_param_parenthesis
manifest = <<-EOF
class foreman::install () {
}
EOF
klasses = Proxy::Puppet::PuppetClass.scan_manifest(manifest)
assert_kind_of Array, klasses
assert_equal 1, klasses.size
klass = klasses.first
assert_equal({}, klass.params)
end
def test_should_extract_parameters__single_param_no_value
manifest = <<-EOF
class foreman::install ($mandatory) {
}
EOF
klasses = Proxy::Puppet::PuppetClass.scan_manifest(manifest)
assert_kind_of Array, klasses
assert_equal 1, klasses.size
klass = klasses.first
assert_equal({'mandatory' => nil}, klass.params)
end
def test_should_extract_parameters__type_coverage
# Note that all keys are string in Puppet
manifest = <<-EOF
class foreman::install (
$mandatory,
$undef = undef,
$emptyString = '',
$emptyStringDq = "",
$string = "foo",
$integer = 42,
$float = 3.14,
$array = ['', "", "foo", 42, 3.14],
$hash = { unquoted => '', "quoted" => "", 42 => "integer", 3.14 => "float", '' => 'empty' },
$complex = { array => ['','foo',42,3.14], hash => {foo=>"bar"}, mixed => [{foo=>bar},{bar=>"baz"}] }
) {
}
EOF
klasses = Proxy::Puppet::PuppetClass.scan_manifest(manifest)
assert_kind_of Array, klasses
assert_equal 1, klasses.size
klass = klasses.first
assert_equal({
'mandatory' => nil,
'undef' => '',
'emptyString' => '',
'emptyStringDq' => '',
'string' => 'foo',
'integer' => 42,
'float' => 3.14,
'array' => ['', '', 'foo', 42, 3.14],
# All keys must be strings
'hash' => { 'unquoted' => '', 'quoted' => '', '42' => 'integer', '3.14' => 'float', '' => 'empty' },
'complex' => { 'array' => ['','foo',42,3.14], 'hash' => {'foo'=>'bar'}, 'mixed' => [{'foo'=>'bar'},{'bar'=>'baz'}] }
}, klass.params)
end
def test_should_handle_import_in_a_manifest
klasses = Proxy::Puppet::PuppetClass.scan_directory('./test/fixtures/modules_include')
assert_kind_of Array, klasses
assert_equal 2, klasses.size
klass = klasses.find {|k| k.name == "sub::foo" }
assert klass
assert_equal "testinclude", klass.module
klass = klasses.find {|k| k.name == "testinclude" }
assert klass
end
#TODO add scans to a real puppet directory with modules
end

Also available in: Unified diff