У меня есть довольно базовый c кукольный модуль для веб-сервиса под управлением tomcat. Я хочу настроить logrotate в файле Tomcat catalina.out, и я хочу начать с написания теста, который подтверждает, что logrotate включен в модуль и настроен с правильными настройками.
Это звучит очень разумно. Однако, это ...
Вот урезанная версия моего init.pp, например:
class my_module::webservice (
...
){
... в лучшем случае плохая практика. Если он вообще существует, то манифест init.pp
модуля my_module
должен определять только класс my_module
. Класс с именем my_module::webservice
должен быть определен в манифесте с именем webservice.pp
в модуле my_module
. Ожидаемое расположение модулей задокументировано в онлайн-документации Puppet. Хотя вы, возможно, сможете избежать определенных расхождений с этими спецификациями, у этого есть только недостатки.
На данный момент я замечаю, что «внутренний класс» не является идиоматическим c Терминология кукол, и это предполагает недопонимание того, с чем вы работаете. В частности, этот ...
logrotate::rule { 'tomcat':
[...]
... вообще не объявляет класс , но вместо этого объявляется ресурс типа logrotate::rule
, который, очевидно, является определенным типом, предоставляемым модулем puppet / logrotate. В общем, объявление ресурса не подразумевает ничего о классах из модуля (если есть), который предоставляет тип ресурса.
Кроме того, хотя вполне возможно, что объявление ресурса logrotate::rule
действительно вызывает класс logrotate
если он будет включен в каталог, это будет деталь реализации logrotate::rule
, и поэтому ваши spe c тесты не должны его тестировать. Только если ожидается, что my_module::webservice
сам объявит класс logrotate
, если его тесты проверят это.
Вы go скажете:
Это не работает (если я удаляю блок logrotate из init.pp, тогда тесты по-прежнему проходят):
it { is_expected.to contain_class('logrotate::conf') }
Вы не предоставили достаточно кода, чтобы мы могли определить, почему тесты проходят, когда они включены в их, но что-то очень странное, если когда-либо это ожидание оправдается. logrotate::conf
также является определенным (ресурсным) типом, а не классом, поэтому ожидание никогда не будет успешным. И, следуя теме, которую я представил выше, если класс my_module::webservice
не объявляет какой-либо ресурс logrotate::conf
напрямую, его тесты не должны проверять его на наличие.
и не запрашивать с помощью:
it { is_expected.to contain_class('logrotate') \
.with('path' => '/var/log/tomcat/catalina.out',
'rotate' => 1,
'rotate_every' => 'day',
'copytruncate' => true,
'missingok' => true,
'compress' => true,
'delaycompress' => true,
)
}
Конечно, это не удается. Он выражает ожидание объявления класса logrotate
, но на самом деле вы объявили ресурс типа logrotate::rule
. Даже если logrotate::rule
объявит logrotate
, никто не будет ожидать, что он передаст свой собственный список параметров.
, и при этом не будет отдельного / вложенного блока описания:
describe 'logrotate::rule' do
[...]
Опять же, это не удивительно. Такой describe
блок сообщает RSpe c, что logrotate::rule
является тестируемым классом. Это не только тестируемый класс (то есть, конечно, my_module::webservice
), но, опять же, logrotate::rule
вообще не является классом. RSpe c также может тестировать определенные типы, но это не то, что вам нужно.
Чтобы проверить, объявлен ли ресурс тестируемым классом , используется предикат вида contain_
тип (
title )
, где любые разделители пространства имен (::
) в имени типа заменяются двойными подчеркиваниями. Например:
it do
is_expected.to contain_logrotate__rule('tomcat')
end
Разрешено, но не обязательно, включать одно или несколько предложений with
для указания ожиданий объявленных параметров назначенного ресурса. После того, что вы, похоже, пытались сделать, возможно, это будет более полно express то, что вы ищете:
require 'spec_helper'
describe 'my_module::webservice' do
on_supported_os.each do |os, os_facts|
context "on #{os}" do
let(:facts) { os_facts }
it do
is_expected.to compile
is_expected.to contain_logrotate__rule('tomcat')
.with(
path: '/var/log/tomcat/catalina.out',
rotate: 1,
rotate_every: 'day',
copytruncate: true,
missingok: true,
compress: true,
delaycompress: true
)
end
end
end
end
Кстати, обратите внимание, что когда вы хотите проверить несколько предикатов на одном и том же примере, существенно эффективнее сгруппировать их в один блок it
, как показано выше, чем помещать каждый в его собственный it
блок. Например, вы, вероятно, заметите разницу во времени выполнения теста даже от объединения всего двух it
блоков в один.
Кроме того, мой пример выше демонстрирует стиль кодирования, близкий к тому, который требуется, чтобы избежать предупреждений от pdk validate
, что подводит нас к еще одному пункту: всегда полезно проверить, что pdk validate
завершается без ошибок или предупреждений, прежде чем пытаться выполнить модульные тесты. Возможно, вы обнаружите, что он чрезмерно требователен как к Puppet, так и к стилю кода Ruby, но он также обнаружит некоторые проблемы, которые приводят к таинственным сбоям тестирования. Кроме того, он работает намного быстрее, чем тесты, и обнаружит практически все синтаксические ошибки как в коде Puppet, так и в Ruby. Расстраивает, что ваши тесты долго не срабатывают из-за незначительной синтаксической ошибки.