Большое спасибо 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/