Проверить наличие внутреннего класса с помощью RSpec и PDK
У меня есть довольно простой модуль марионеток для веб-сервиса под управлением tomcat. Я хочу настроить logrotate на Tomcatcatalina.out
файл, и я хочу начать с написания теста, подтверждающего, что logrotate включен в модуль и настроен с правильными настройками.
Вот урезанная версия моего webservice.pp
, например:
class my_module::webservice (
...
){
include ::tomcat_server
...
logrotate::rule { 'tomcat':
path => '/var/log/tomcat/catalina.out',
rotate => 1,
rotate_every => 'day',
copytruncate => true,
missingok => true,
compress => true,
delaycompress => true,
}
}
и я включил модуль logrotate forge в свой .fixtures.yml
вот так:
fixtures:
forge_modules:
logrotate:
repo: 'puppet-logrotate'
ref: '3.2.1'
...
Но я могу написать только тест, подтверждающий, что logrotate
входит в модуль так:
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 { is_expected.to compile }
it { is_expected.to contain_class('logrotate') }
end
end
end
Это не сработает (если я удалю блок logrotate из init.pp
тогда тесты еще проходят):
it { is_expected.to contain_class('logrotate::conf') }
и не просит with
:
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,
)
}
а также отдельный / вложенный describe
блок:
describe 'logrotate::rule' do
let(:title) { 'tomcat' }
let(:params) do
{
'path' => '/var/log/tomcat/catalina.out',
'rotate' => 1,
'rotate_every' => 'day',
'copytruncate' => true,
'missingok' => true,
'compress' => true,
'delaycompress' => true,
}
end
end
Я не могу найти ничего в документах rspec, в которых упоминается что-либо, кроме проверки определения класса. Возможно ли вообще то, что я пытаюсь сделать?
Вот мой макет каталога:
puppet
`- modules
`- my_module
|- data
|- manifests
| |- init.pp
| `- webservice.pp
|- spec
| |- classes
| | `- webservice_spec.rb
| `- spec_helper.rb
|- .fixtures.yml
|- Gemfile
|- hiera.yaml
|- metadata.json
`- Rakefile
1 ответ
У меня есть довольно простой модуль марионеток для веб-сервиса под управлением 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. Хотя вам, возможно, удастся избежать некоторых расхождений с этими спецификациями, в этом есть только обратная сторона.
На этом этапе я заметил, что "внутренний класс" - это не идиоматическая терминология Марионетки, и он предполагает неправильное понимание того, с чем вы работаете. Конкретно это...
logrotate::rule { 'tomcat':
[...]
... не объявляет класс вообще, а объявляет ресурс типаlogrotate::rule
, который, по-видимому, является определенным типом, предоставляемым модулем puppet/logrotate. В общем, объявление ресурса ничего не говорит о классах из модуля (если таковой имеется), который предоставляет тип ресурса.
Кроме того, хотя вполне возможно, что объявление logrotate::rule
ресурс действительно вызывает класс logrotate
для включения в каталог, это будет деталью реализации logrotate::rule
, и поэтому ваши спецификации не должны проверять его. Только еслиmy_module::webservice
ожидается, что сам объявит класс logrotate
если его тесты проверяют это.
Вы продолжаете говорить:
Это не сработает (если я удалю блок logrotate из init.pp, тесты все равно пройдут):
it { is_expected.to contain_class('logrotate::conf') }
Вы не представили нам достаточно кода, чтобы определить, почему тесты проходят, когда он включен в них, но что-то очень странно, если это ожидание когда-либо оправдывается. logrotate::conf
также является определенным (ресурсным) типом, а не классом, поэтому ожидание никогда не должно быть успешным. И следуя теме, которую я представил выше, если classmy_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
блок сообщает RSpec, что logrotate::rule
это тестируемый класс. Мало того, что это не тестируемый класс (это, конечно,my_module::webservice
), но, опять же, logrotate::rule
это вообще не класс. RSpec, безусловно, может тестировать и определенные типы, но это не то, что вам нужно.
Чтобы проверить, объявлен ли ресурс тестируемым классом, используется предикат формыcontain_
тип(
заглавие)
, где любые разделители пространства имен (::
) в названии типа заменяются двойным подчеркиванием. Например:
it do
is_expected.to contain_logrotate__rule('tomcat')
end
Разрешено, но необязательно, включать один или несколько with
пункты, чтобы указать ожидания заявленных параметров назначенного ресурса. После того, что вы, кажется, пытались сделать, возможно, это более полно выразит то, что вы ищете:
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. Очень неприятно, что ваши тесты долго терпят неудачу из-за незначительной синтаксической ошибки.