Большое спасибо Atlassian за предоставленную мне возможность опубликовать этот сериал !!
В нашем предыдущем посте, посвященном созданию версий Puppet , мы описали самую базовую проверку, чтобы убедиться, что манифест Puppet действителен. Мы использовали функцию parseonly, чтобы посмотреть, скомпилируется ли она.
До тех пор, пока мы не узнаем, это означает, что у нас есть, только если компилятор доволен , а не выполняет функцию, которая ему необходима. В 2009 году, после первых дней занятий, я написал коллекцию ссылок, управляемых тестовой инфраструктурой . Это было очевидно вдохновлено разговором Линдсей Холмвуд о огурец-нагио .
На фронте шеф-повара Opscode Стивен Нельсон-Смит написал отличную книгу о том, как это сделать, с помощью Chef . Также см. Проект cuken, где сгруппированы повторно используемые шаги огурца.
Поскольку мы используем Puppet здесь, в Atlassian, я не мог понять текущее состояние тестирования кукол. Многое уже можно найти по адресу http://puppetlabs.com/blog/testing-modules-in-the-puppet-forge/
Обратите внимание, что я специально назвал этот блог «Кукольным модульным тестированием», так как тесты, которые я сейчас описываю, не работают на реальной системе. Поэтому трудно проверить реальное поведение.
Совет 1: огурец-марионетка
Вдохновленный рассказом Линдси Холмвуд о огурец-нагио и манекенщицей Охада Леви, Николай Штурм создал кукольную куклу
В своем посте « Мысли о тестировании кукольных манифестов» он объясняет, что идея написания тестов НЕ заключается в дублировании кода, и он определил наиболее распространенные проблемы, с которыми он сталкивается:
- каталог не компилируется: синтаксические ошибки, отсутствующие файлы шаблона, ..
- каталог компилируется, но не может быть применен: недоступные или несуществующие ресурсы, недостающие файловые ресурсы в репо
- Каталог действительно применяется, но он неисправен: дефектные файлы, из-за пустых переменных манифеста или неправильных значений, отсутствующих зависимостей (неправильный порядок …), файлы устанавливаются без обеспечения каталога …
Важный совет:
Спецификации ресурса могут быть полезны для целей документации или рефакторинга. Тем не менее, существует риск повторной реализации манифеста Puppet, так что будьте осторожны.
$ cd puppet-mymodule $ gem install cucumber-puppet
Напишите функции для каждого модуля, это структура, к которой мы стремимся:
module
+-- manifests
+-- lib
+-- features
+-- support
| +-- hooks.rb
| +-- world.rb
+-- catalog
+-- feature..
Создайте огуречно-кукольный мир:
$ cucumber-puppet-gen world
Generating with world generator:
[ADDED] features/support/hooks.rb
[ADDED] features/support/world.rb
[ADDED] features/steps
# Adjust the paths to your modules and manifests
$ cat features/support/hooks.rb
Before do
# adjust local configuration like this
# @puppetcfg['confdir'] = File.join(File.dirname(__FILE__), '..', '..')
# @puppetcfg['manifest'] = File.join(@puppetcfg['confdir'], 'manifests', 'site.pp')
# @puppetcfg['modulepath'] = "/srv/puppet/modules:/srv/puppet/site-modules"
# adjust facts like this
@facts['architecture'] = "i386"
end
# Nothing exciting here
$ cat features/support/world.rb
require 'cucumber-puppet/puppet'
require 'cucumber-puppet/steps'
World do
CucumberPuppet.new
end
Создание функции политики:
$ cucumber-puppet-gen policy
Generating with policy generator:
[ADDED] features/catalog
# Notice the <hostname>.example.com.yaml
# These files contain the facts to test your catalog against
#
$ cat features/catalog/policy.feature
Feature: General policy for all catalogs
In order to ensure applicability of a host's catalog
As a manifest developer
I want all catalogs to obey some general rules
Scenario Outline: Compile and verify catalog
Given a node specified by "features/yaml/<hostname>.example.com.yaml"
When I compile its catalog
Then compilation should succeed
And all resource dependencies should resolve
Examples:
| hostname |
| localhost |
Для фактического запуска:
$ cucumber-puppet features/catalog/policy.feature
Feature: General policy for all catalogs
In order to ensure applicability of a host's catalog
As a manifest developer
I want all catalogs to obey some general rules
Scenario Outline: Compile and verify catalog # features/catalog/policy.feature:6
Given a node specified by "features/yaml/<hostname>.example.com.yaml" # cucumber-puppet-0.3.6/lib/cucumber-puppet/steps.rb:1
When I compile its catalog # cucumber-puppet-0.3.6/lib/cucumber-puppet/steps.rb:14
Then compilation should succeed # cucumber-puppet-0.3.6/lib/cucumber-puppet/steps.rb:48
And all resource dependencies should resolve # cucumber-puppet-0.3.6/lib/cucumber-puppet/steps.rb:28
Examples:
| hostname |
| localhost |
Cannot find node facts features/yaml/localhost.example.com.yaml. (RuntimeError)
features/catalog/policy.feature:7:in `Given a node specified by "features/yaml/<hostname>.example.com.yaml"'
Failing Scenarios:
cucumber features/catalog/policy.feature:6 # Scenario: Compile and verify catalog
1 scenario (1 failed)
4 steps (1 failed, 3 skipped)
0m0.006s
Список команд:
Generators for cucumber-puppet
Available generators
feature Generate a cucumber feature
policy Generate a catalog policy
testcase Generate a test case for the test suite
testsuite Generate a test suite for puppet features
world Generate cucumber step and support files
General options:
-p, --pretend Run, but do not make any changes.
-f, --force Overwrite files that already exist.
-s, --skip Skip files that already exist.
-d, --delete Delete files that have previously been generated with this generator.
--no-color Don't colorize the output
-h, --help Show this message
--debug Do not catch errors
Он также добавил поддержку для тестирования exported-ресурсов .
- Я обнаружил, что это не очень ясно из документации, я лучше понял основы, когда смотрел хороший видеоурок по огуречной марионетке, который дал Том Салстон .
- Общая информация о огурце может быть найдена в книге прагматичных программистов «Огурец»
- Или на основном сайте огурца http://cukes.info/
А для более практического объяснения посмотрите, как Оливер Хокинс описывает, как Nokia использует огуречную марионетку
Scenario: Proxy host and port have sensible defaults
Given a node of class "mymodule::myapp"
And we have loaded "test" settings
And we have unset the fact "proxy_host"
And we have unset the fact "proxy_port"
When I compile the catalog
Then there should be a file "/etc/myapp/config.properties"
And the file should contain "proxy.port=-1"
And the file should contain /proxy\.host=$/
----
Then /^the file should contain "(.*)"$/ do |text|
fail "File parameter 'content' was not specified" if @resource["content"].nil?
fail "Text content [#{text}] was not found" unless @resource["content"].include?(text)
end
Then /^the file should contain \/([^\"].*)\/$/ do |regex|
fail "File parameter 'content' was not specified" if @resource["content"].nil?
fail "Text regex [/#{regex}/] did not match" unless @resource["content"] =~ /#{regex}/
end
Совет 2: rspec-puppet
Хотя идея использования specs и puppet не нова ( https://github.com/jes5199/puppet_spec ), новый инструмент в блоке — rspec-puppet, предложенный нам Тимом Шарпом . Тот же человек, который дал нам vim-puppet и puppet-lint
Как и в случае структуры cucumber-puppet, идея заключается в том, чтобы каталог specs был близок к вашему модулю:
module
+-- manifests
+-- lib
+-- spec
+-- spec_helper.rb
+-- classes
| +-- <class_name>_spec.rb
+-- defines
| +-- <define_name>_spec.rb
+-- functions
+-- <function_name>_spec.rb
Я нашел полезным изменить по умолчанию spec_helper.rb по умолчанию
require 'rspec-puppet'
RSpec.configure do |c|
c.module_path = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
c.manifest_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', '..','..','manifests'))
end
desc "Run specs check on puppet manifests"
RSpec::Core::RakeTask.new(:spec) do |t|
t.pattern = './demo-puppet/modules/**/*_spec.rb' # don't need this, it's default
t.verbose = true
t.rspec_opts = "--format documentation --color"
# Put spec opts in a file named .rspec in root
end
Вот быстрый пример проверки, устанавливает ли класс apache пакет httpd в системе Debian.
require "#{File.join(File.dirname(__FILE__),'..','spec_helper')}"
describe 'apache', :type => :class do
let (:title { 'basic' })
let(:params) { { } }
let(:facts) { {:operatingsystem => 'Debian', :kernel => 'Linux'} }
it { should contain_package('httpd').with_ensure('installed') }
end
Более подробное описание можно найти на
Для получения более общей информации о rspec:
- Основной сайт, чтобы найти все ожидания, издевается и т.д .. http://rspec.info/documentation/
- Книга о Rspec от прагматических программистов — http://pragprog.com/book/achbd/the-rspec-book
Вывод огурец-марионетка против rspec-puppet
Я думаю, что вы можете написать свои тесты в обоих, чтобы сделать то же самое. В настоящее время они оба поддерживают 2.6 и 2.7
Я нашел rspec-puppet немного проще для манипуляции с такими параметрами, как: имя или: факты. Файл yaml не показался мне гибким. Также огурец, кажется, устанавливает больше зависимых драгоценных камней, которые могут нанести вред другим проектам.
Но как уже сказал Николай:
«Не дублируйте свои манифесты в своих тестах» Сосредоточьтесь на проблемах каталога, которые он описал ранее, и проверьте свою логику. Не проверяйте, выполняет ли кукол свою работу, проверяйте, что ваша логика выполняет свою работу.
Вот почему я назвал их юнит-тестами, они не тестируют реальную функциональность. (Это для следующего поста в блоге)
Совет 3: кукольный линт
Чтобы проверить ваши файлы на предмет стиля программирования, вы можете использовать https://github.com/rodjek/puppet-lint . Он проверит правила для интервалов, идентификаторов и пробелов, цитирования, ресурсов, условий, классов
Простой способ интегрировать его в ваш Rakefile:
require 'puppet-lint'
desc "Run lint check on puppet manifests"
task :lint do
linter = PuppetLint.new
Dir.glob('./demo-puppet/modules//**/*.pp').each do |puppet_file|
puts "Evaluating #{puppet_file}"
linter.file = puppet_file
linter.run
end
fail if linter.errors?
end
Теперь вы можете просто запустить:
$ rake lint
Совет 4: сойти с ума и создать собственную логику тестирования / каталога
Посмотрев на логику rspec-puppet, я посмотрел глубже, как пройти через объект каталога. Это в значительной степени работа в процессе, но идея состоит в том, чтобы найти способ посмотреть на изменения в каталоге.
Ниже приведен список полезных примеров понимания того, как работать с puppet в коде ruby:
Первый список ссылок — это несколько забавных инструментов, написанных Дином Уилсоном из известной www.puppetcookbook.com :
- http://www.unixdaemon.net/tools/puppet/puppet-cucumber-providers.html
- http://www.unixdaemon.net/tools/puppet/listing-puppet-managed-files.html
- https://github.com/deanwilson/puppet-scripts/blob/master/puppet-ls
- https://github.com/deanwilson/puppet-scripts/blob/master/puppet-pkg
- https://github.com/deanwilson/puppet-scripts/blob/master/pm-grep
RI Pienaar из Mcollective Fame демонстрирует способ создания различий в каталоге. это может быть полезно, чтобы понять, какие тесты нужно запускать между изменениями:
- http://www.devco.net/archives/2010/11/14/getting_diffs_for_puppet_catelogs.php
-
Значительно лучшие инструменты CLI для взаимодействия с Puppet: https://github.com/lak/puppet-interfaces
-
И еще один забавный инструмент — puppet-growl, который будет запускать проверку синтаксиса файла кукол каждый раз, когда файл изменяется в каталоге.
В этой последней главе показано, как пройти по каталогу и проверить доступные классы и ресурсы:
Источник:
http://www.jedi.be/blog/2011/12/05/puppet-unit-testing-like-a-pro/