我如何模拟事实来测试对事实进行十进制乘法的 Puppet 模板?
How can I mock facts to test a Puppet template that does decimal multiplication on a fact?
上下文:
我有一个 puppet 模板,它在呈现时处理 processors
事实的 count
子组件。我所有的客户都存在这个事实。
事实的用例在对其执行十进制数学运算的模板行中,例如:MyConfigVar=<%= 0.9 * @processors['count'] %>
在某些 .erb
文件中。
我想:
- 将我的模板代码部署到生产主机。
- 为我的模板编写健壮的单元测试,这样我就可以确定它会正确呈现,给定各种合理的事实值。
我试过的:
首先,我尝试使用印记:<%= 0.9 * @processors[:count] %>
。如果我用 rspec-puppet 嘲笑 facts = { :processors => { :count => 10 } }
之类的东西,我的测试都通过了。清单应用程序不起作用;它有一个 "can't multiply nil
" 错误。印记显然已经用完了。
然后,我尝试使用字符串键:<%= 0.9 * @processors['count'] %>
。我对印记 (facts = { :processors => { :count => 10 } }
) 的测试没有被接受,但我的值被正确找到并乘以 facts = { :processors => { 'count' => 10 } }
。然后所有测试都通过了。但是,清单应用程序因 Can't coerce String into Int
失败而失败。
然后,我尝试使用字符串值。模板仍然是 <%= 0.9 * @processors['count'].to_i %>
,我测试了字符串和整数值,例如
let(:facts) { :processors => { 'count' => '10' } }
# tests with string value
let(:facts) { :processors => { 'count' => 10 } }
# tests with integer value
测试全部通过,但清单应用程序呈现 0.0
事实值。
问题:
两个主要问题:
- 如何可靠地使用此(或任何)事实进行内联十进制数学运算?
- 我如何可靠地进行单元测试,使用
rspec-puppet
或类似的,实际上模拟生产代表类型的值?
为了它的价值,我对你的问题做了一些调查,在我的测试台上 'processors' 事实上,而当 运行 facter processors
时的散列实际上是一个字符串一旦它进入 Puppet/templates 并且它缺少任何分隔符(即 "modelsIntel(R) Core(TM) i7-2760QM CPU @ 2.40GHzcount1physicalcount1" 是原始值)。我通过在我的 ruby 模板中使用“@processors.class”以及其他一些测试来验证这一点。我的测试平台是 运行 Puppet 3.8.3 和 Facter 2.4.6,以防出现影响。
所以我可以提出的解决方案是:
- 使用@processorcount 事实,它始终是一个整数,并且在您的单元测试中应该可以很好地处理印记。
直接在你的模板中使用 Facter(这不是傀儡,但它有效)
<%= Facter.value(:processors)['count'] %>
使用正则表达式字符串解析(我不推荐这样做,因为它很脆弱而且很老套,但它确实可以解决问题)
count=@processors.dup.gsub!(/physicalcount/,'physical').gsub!(/.*count([0-9])+.*/,'')
很可能在不同版本的 Puppet/Facter 中这不是问题,但希望这足以让您朝着正确的方向前进。
这里有几件事在起作用。
正如 Josh Souza 所说,旧版本的 Facter 不支持散列或数组。因此,根据您使用的 Puppet 和 Facter 的版本,我会检查 stringify_facts 配置的值。
如果将其设置为 true(它将在较旧的 Puppet 上设置),那么事实将不会以散列的形式出现,它们会转换为清单中的字符串,从而导致没有分隔的混搭字符串(例如. modelsIntel(R) Core(TM) i7-2760QM CPU @ 2.40GHzcount1physicalcount1
)。请注意 count1
,在原始哈希中应该是 :count => 1
。
您可以在 rspec-puppet >= 2.2 中使用 spec_helper 中的 stringify_facts
设置进行测试。
因此,如果您 运行 facter -p
:
,您可以看到许多不是散列的遗留事实
$ facter -p | grep processor
processorcount => 8
processors => {"count"=>8, "speed"=>"2.5 GHz"}
sp_current_processor_speed => 2.5 GHz
sp_number_processors => 4
所以我建议使用 $::processorcount
事实,它应该是一个整数,因为这是 returned 的值,但您可以使用 to_i
来确定您的 .erb
模板。我很确定它应该总是 return 一个整数。
如果您真的很勇敢,可以创建一个函数将值转换为数字并在您的清单中使用它(例如 https://github.com/kwilczynski/puppet-functions/blob/master/lib/puppet/parser/functions/str2num.rb)
因此您的代码如下所示:
if (is_integer($::processorcount)) {
$processor_as_int = $::processorcount
} else {
$processor_as_int = str2num($::processorcount)
}
总而言之,有点乱,你可以在Puppet 4中看到为什么we have a much tighter typing system!
上下文:
我有一个 puppet 模板,它在呈现时处理 processors
事实的 count
子组件。我所有的客户都存在这个事实。
事实的用例在对其执行十进制数学运算的模板行中,例如:MyConfigVar=<%= 0.9 * @processors['count'] %>
在某些 .erb
文件中。
我想:
- 将我的模板代码部署到生产主机。
- 为我的模板编写健壮的单元测试,这样我就可以确定它会正确呈现,给定各种合理的事实值。
我试过的:
首先,我尝试使用印记:<%= 0.9 * @processors[:count] %>
。如果我用 rspec-puppet 嘲笑 facts = { :processors => { :count => 10 } }
之类的东西,我的测试都通过了。清单应用程序不起作用;它有一个 "can't multiply nil
" 错误。印记显然已经用完了。
然后,我尝试使用字符串键:<%= 0.9 * @processors['count'] %>
。我对印记 (facts = { :processors => { :count => 10 } }
) 的测试没有被接受,但我的值被正确找到并乘以 facts = { :processors => { 'count' => 10 } }
。然后所有测试都通过了。但是,清单应用程序因 Can't coerce String into Int
失败而失败。
然后,我尝试使用字符串值。模板仍然是 <%= 0.9 * @processors['count'].to_i %>
,我测试了字符串和整数值,例如
let(:facts) { :processors => { 'count' => '10' } }
# tests with string value
let(:facts) { :processors => { 'count' => 10 } }
# tests with integer value
测试全部通过,但清单应用程序呈现 0.0
事实值。
问题:
两个主要问题:
- 如何可靠地使用此(或任何)事实进行内联十进制数学运算?
- 我如何可靠地进行单元测试,使用
rspec-puppet
或类似的,实际上模拟生产代表类型的值?
为了它的价值,我对你的问题做了一些调查,在我的测试台上 'processors' 事实上,而当 运行 facter processors
时的散列实际上是一个字符串一旦它进入 Puppet/templates 并且它缺少任何分隔符(即 "modelsIntel(R) Core(TM) i7-2760QM CPU @ 2.40GHzcount1physicalcount1" 是原始值)。我通过在我的 ruby 模板中使用“@processors.class”以及其他一些测试来验证这一点。我的测试平台是 运行 Puppet 3.8.3 和 Facter 2.4.6,以防出现影响。
所以我可以提出的解决方案是:
- 使用@processorcount 事实,它始终是一个整数,并且在您的单元测试中应该可以很好地处理印记。
直接在你的模板中使用 Facter(这不是傀儡,但它有效)
<%= Facter.value(:processors)['count'] %>
使用正则表达式字符串解析(我不推荐这样做,因为它很脆弱而且很老套,但它确实可以解决问题)
count=@processors.dup.gsub!(/physicalcount/,'physical').gsub!(/.*count([0-9])+.*/,'')
很可能在不同版本的 Puppet/Facter 中这不是问题,但希望这足以让您朝着正确的方向前进。
这里有几件事在起作用。
正如 Josh Souza 所说,旧版本的 Facter 不支持散列或数组。因此,根据您使用的 Puppet 和 Facter 的版本,我会检查 stringify_facts 配置的值。
如果将其设置为 true(它将在较旧的 Puppet 上设置),那么事实将不会以散列的形式出现,它们会转换为清单中的字符串,从而导致没有分隔的混搭字符串(例如. modelsIntel(R) Core(TM) i7-2760QM CPU @ 2.40GHzcount1physicalcount1
)。请注意 count1
,在原始哈希中应该是 :count => 1
。
您可以在 rspec-puppet >= 2.2 中使用 spec_helper 中的 stringify_facts
设置进行测试。
因此,如果您 运行 facter -p
:
$ facter -p | grep processor
processorcount => 8
processors => {"count"=>8, "speed"=>"2.5 GHz"}
sp_current_processor_speed => 2.5 GHz
sp_number_processors => 4
所以我建议使用 $::processorcount
事实,它应该是一个整数,因为这是 returned 的值,但您可以使用 to_i
来确定您的 .erb
模板。我很确定它应该总是 return 一个整数。
如果您真的很勇敢,可以创建一个函数将值转换为数字并在您的清单中使用它(例如 https://github.com/kwilczynski/puppet-functions/blob/master/lib/puppet/parser/functions/str2num.rb)
因此您的代码如下所示:
if (is_integer($::processorcount)) {
$processor_as_int = $::processorcount
} else {
$processor_as_int = str2num($::processorcount)
}
总而言之,有点乱,你可以在Puppet 4中看到为什么we have a much tighter typing system!