我已经建立了一个用于安装Jenkins CI的食谱。它使用key
食谱中的repository
和yum
资源,因此我最终得到以下食谱:
yum_key "RPM-GPG-KEY-jenkins" do
url "http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key"
action :add
end
yum_repository "jenkins" do
description "Jenkins-CI 3rd party repository"
url "http://pkg.jenkins-ci.org/redhat"
key "RPM-GPG-KEY-jenkins"
action :add
end
当我将这个食谱包含在另一个食谱中时:
include_recipe 'sp_jenkins::default'
我用以下ChefSpec测试
测试it 'includes the `sp_jenkins::default` recipe' do
expect(chef_run).to include_recipe('sp_jenkins::install')
end
我的ChefSpec测试失败,输出如下:
NameError:
Cannot find a resource for yum_key on chefspec version 0.6.1
(我不确定为什么会说版本0.6.1,gem list
告诉我它使用的是3.0.2)
sp_jenkins
食谱确实取决于yum
食谱(metadata.rb),并且运行正常,但是,我目前正在撰写的食谱不依赖于{{1} } cookbook因此没有yum
和yum_key
方法可用。
有没有办法阻止ChefSpec下降'纳入食谱/食谱,只测试当前的食谱?
答案 0 :(得分:3)
Ohai! Julian是正确的 - ChefSpec实际上在本地机器上运行Chef Solo。它将提供者操作重写为noop,但会创建所有操作的注册表(包括执行通知时将采取的操作)。
因此,就像您需要yum
食谱将此食谱汇总到一个真实节点上一样,您需要在使用ChefSpec进行单元测试时将其汇总。完成此任务的最简单方法是使用Berkshelf或Librarian解析器。要在require 'chefspec/berkshelf'
之后使用Berkshelf resolver,只需chefspec
:
# spec_helper.rb
require 'chefspec'
require 'chefspec/berkshelf'
如果您的系统上安装了Berkshelf,它会将所有cookbook拉入临时目录并为您运行ChefSpec。
您可能还想看一下旨在解决类似问题的Strainer。
在某种程度上不相关的说明中,我正在研究一种可能更适合您需求的large refactor to the Jenkins cookbook。
来源:
答案 1 :(得分:2)
不,没有办法阻止它下降,因为它试图将整个Chef运行在内存中。
但是,如果你在ChefSpec中使用Berkshelf功能,那么Berkshelf依赖解析器会将所有依赖的cookbook提供给内存中的Chef运行,你就会变得很好。
答案 2 :(得分:0)
期望单独测试您的食谱 绝对正确,并且不要将其他项目的代码包括在测试范围内。不幸的是,我发现似乎没有受支持的“干净”方法来执行此操作。我能够做到这一点,但这是有代价的。
要使用此技术,请不要require 'chefspec/berkshelf'
chefspec
本身在测试代码中的任何位置,因为您有意不收集其他食谱源代码。这是我的工作测试模块的模板(不是我的完整测试代码,因为我省略了RSpec配置选项):
describe 'mycookbook::recipe' do
let(:chef_run) do
ChefSpec::SoloRunner.new(platform: 'x', version: 'x') {
# ...
}.converge(described_recipe)
end
before :each do
allow_any_instance_of(Chef::RunContext::CookbookCompiler).to receive(:cookbook_order) do
Chef::Log.debug 'Attempt to source external cookbooks blocked'
[described_cookbook]
end
allow_any_instance_of(Chef::Recipe).to receive(:include_recipe) do |recipe|
Chef::Log.debug "Attempt to include #{recipe} blocked"
end
end
it 'works' do
# ...
end
end
您的before
中都需要这两个。我必须为之工作的是拦截:cookbook_order
方法。我必须深入研究Chef的内部知识才能发现这一点。请记住,这对于使用Chef 14的我来说是有效的,但不能保证这将是未来安全的。如果CookbookCompiler
的实现发生变化,则升级Chef之后,您可能必须找到其他解决方案。 (但是Chef::Recipe.include_recipe
的拦截是受支持的API,因此至少在将来会更安全。)
而且,我提到这是有代价的。 (除了使用不受支持的黑客!),除非您自己的食谱内,否则您将无法对食谱或属性包含的任何expect
做任何操作。像这样的测试用例将失败,因为实际上不能包含配方,因为您正在防止这种情况:
it 'includes othercookbook::recipe' do
expect_any_instance_of(Chef::Recipe).to receive(:include_recipe).with('othercookbook::recipe')
end
此外,您现在必须在before
块中满足所有属性和其他先决条件,否则运行列表中的其他配方可能会满足这些条件和其他先决条件。因此,您可能会为此付出巨大的痛苦。但是,一旦完成,您的脆性测试就会少得多。 (尽管要获得100%的外部依赖关系纯度,您还必须交出fauxhai
,这会更加痛苦。)