Add a new custom matcher render_config_file to test ini file content

After this, you can use below way to test ini file content:
render_config_file(file).with_section_content(section, content)

Change-Id: Iaed80a3fc61db02324fb2c8166b7032fd1823f60
This commit is contained in:
Chen Zhiwei 2014-12-09 11:06:49 +08:00
parent 47ba1660b9
commit d99aacda7c
6 changed files with 258 additions and 129 deletions

View File

@ -11,6 +11,7 @@ This file is used to list changes made in each version of cookbook-openstack-com
* Add OS_VOLUME_API_VERSION for openrc
* Removed the hardcoded PPA reference to "Precise"
* Added an optional automatic apt-get update for Debian based repos
* Add a new custom matcher render_config_file to test ini file content
## 10.1.0
* Adding identity admin bind host endpoint to allow flexibility and consistency

View File

@ -121,6 +121,7 @@ This cookbook exposes a set of default library routines:
* `db_create_with_user` -- Creates a database and database user for a named OpenStack database
* `secret` -- Returns the value of an encrypted data bag for a named OpenStack secret key and key-section
* `get_password` -- Ease-of-use helper that returns the decrypted password for a named database, service or keystone user.
* `matchers` -- A custom matcher(render_config_file) for testing ini format file section content by with_section_content.
Usage
-----

87
libraries/matchers.rb Normal file
View File

@ -0,0 +1,87 @@
# encoding: UTF-8
if defined?(ChefSpec)
#
# Test method for ini format file
#
# Example file content:
#
# [section1]
# option1 = value1
# option2 = value2
# [section2]
# option1 = value2
#
# Example custom matcher that can be called in other
# dependends cookbooks.
#
# render_config_file(path).with_section_content(
# 'section1', 'option1 = value1')
# render_config_file(path).with_section_content(
# 'section1', /^option2 = value2$/)
#
def render_config_file(path)
RenderConfigFileMatcher.new(path)
end
#
# Extend the RenderFileMatcher as RenderConfigFileMatcher,
# add a new method with_section_content for ini format file.
#
class RenderConfigFileMatcher < ChefSpec::Matchers::RenderFileMatcher
def with_section_content(section, expected_content)
@section = section
@expected_content = expected_content
self
end
# rubocop:disable MethodLength, CyclomaticComplexity
def matches_content?
def section?(line, section = '.*')
if line =~ /^[ \t]*\[#{section}\]/
return true
else
return false
end
end
def get_section_content(content, section)
match = false
section_content = ''
content.split("\n").each do |line|
if section?(line, section)
match = true
next
end
section_content << "#{line}\n" if match == true && !section?(line)
break if match == true && section?(line)
end
section_content
end
return true if @expected_content.nil?
@actual_content = ChefSpec::Renderer.new(@runner, resource).content
unless @actual_content.nil?
unless @section.nil?
@actual_content = get_section_content(@actual_content, @section)
end
end
return false if @actual_content.nil?
if @expected_content.is_a?(Regexp)
@actual_content =~ @expected_content
elsif RSpec::Matchers.is_a_matcher?(@expected_content)
@expected_content.matches?(@actual_content)
else
@actual_content.include?(@expected_content)
end
end
# rubocop:enable MethodLength, CyclomaticComplexity
end
end

View File

@ -18,5 +18,6 @@ end
depends 'apt', '>= 2.3.8'
depends 'database', '>= 2.0.0'
depends 'mysql', '< 6.0.0'
depends 'yum', '>= 3.1.4'
depends 'yum-epel', '>= 0.3.4'

View File

@ -46,155 +46,200 @@ describe 'openstack-common::logging' do
'ignore.key.1' => 'ignore.value.1',
'ignore.key.2' => 'ignore.value.2'
}
[
/^\[loggers\]$/,
/^keys=.*ignore_key_1,ignore_key_2$/
].each do |content|
expect(chef_run).to render_file(file.name).with_content(content)
end
expect(chef_run).to render_config_file(file.name)
.with_section_content('loggers', /^keys=.*ignore_key_1,ignore_key_2$/)
end
it 'adds specific logger ignore block' do
node.set['openstack']['logging']['ignore'] = {
'test.nova.api.openstack.wsgi' => 'WARNING'
}
content = [
'[logger_test_nova_api_openstack_wsgi]',
[
'level = WARNING',
'handlers = prod,debug',
'qualname = test.nova.api.openstack.wsgi'
]
expect(chef_run).to render_file(file.name).with_content(build_section(content))
].each do |line|
expect(chef_run).to render_config_file(file.name)
.with_section_content('logger_test_nova_api_openstack_wsgi', line)
end
end
end
context 'loggers' do
it 'adds default loggers' do
[
['[loggers]',
'keys=root,ceilometer,cinder,glance,horizon,keystone,nova,'\
'neutron,swift,trove,amqplib,sqlalchemy,boto,suds,eventletwsgi,'\
'nova_api_openstack_wsgi,nova_osapi_compute_wsgi_server'],
['[logger_root]',
'level=NOTSET',
'handlers=devel'],
['[logger_ceilometer]',
'level=DEBUG',
'handlers=prod,debug',
'qualname=ceilometer'],
['[logger_cinder]',
'level=DEBUG',
'handlers=prod,debug',
'qualname=cinder'],
['[logger_glance]',
'level=DEBUG',
'handlers=prod,debug',
'qualname=glance'],
['[logger_horizon]',
'level=DEBUG',
'handlers=prod,debug',
'qualname=horizon'],
['[logger_keystone]',
'level=DEBUG',
'handlers=prod,debug',
'qualname=keystone'],
['[logger_nova]',
'level=DEBUG',
'handlers=prod,debug',
'qualname=nova'],
['[logger_neutron]',
'level=DEBUG',
'handlers=prod,debug',
'qualname=neutron'],
['[logger_swift]',
'level=DEBUG',
'handlers=prod,debug',
'qualname=swift'],
['[logger_trove]',
'level=DEBUG',
'handlers=prod,debug',
'qualname=trove'],
['[logger_amqplib]',
'level=WARNING',
'handlers=stderr',
'qualname=amqplib'],
['[logger_sqlalchemy]',
'level=WARNING',
'handlers=stderr',
'qualname=sqlalchemy'],
['[logger_boto]',
'level=WARNING',
'handlers=stderr',
'qualname=boto'],
['[logger_suds]',
'level=INFO',
'handlers=stderr',
'qualname=suds'],
['[logger_eventletwsgi]',
'level=WARNING',
'handlers=stderr',
'qualname=eventlet.wsgi.server'],
['[logger_nova_api_openstack_wsgi]',
'level=WARNING',
'handlers=prod,debug',
'qualname=nova.api.openstack.wsgi'],
['[logger_nova_osapi_compute_wsgi_server]',
'level=WARNING',
'handlers=prod,debug',
'qualname=nova.osapi_compute.wsgi.server']
].each do |content|
expect(chef_run).to render_file(file.name).with_content(build_section(content))
{
'loggers' =>
[
'keys=root,ceilometer,cinder,glance,horizon,keystone,nova,'\
'neutron,swift,trove,amqplib,sqlalchemy,boto,suds,eventletwsgi,'\
'nova_api_openstack_wsgi,nova_osapi_compute_wsgi_server'
],
'logger_root' =>
[
'level=NOTSET',
'handlers=devel'
],
'logger_ceilometer' =>
[
'level=DEBUG',
'handlers=prod,debug',
'qualname=ceilometer'
],
'logger_cinder' =>
[
'level=DEBUG',
'handlers=prod,debug',
'qualname=cinder'
],
'logger_glance' =>
[
'level=DEBUG',
'handlers=prod,debug',
'qualname=glance'
],
'logger_horizon' =>
[
'level=DEBUG',
'handlers=prod,debug',
'qualname=horizon'
],
'logger_keystone' =>
[
'level=DEBUG',
'handlers=prod,debug',
'qualname=keystone'
],
'logger_nova' =>
[
'level=DEBUG',
'handlers=prod,debug',
'qualname=nova'
],
'logger_neutron' =>
[
'level=DEBUG',
'handlers=prod,debug',
'qualname=neutron'
],
'logger_swift' =>
[
'level=DEBUG',
'handlers=prod,debug',
'qualname=swift'
],
'logger_trove' =>
[
'level=DEBUG',
'handlers=prod,debug',
'qualname=trove'
],
'logger_amqplib' =>
[
'level=WARNING',
'handlers=stderr',
'qualname=amqplib'
],
'logger_sqlalchemy' =>
[
'level=WARNING',
'handlers=stderr',
'qualname=sqlalchemy'
],
'logger_boto' =>
[
'level=WARNING',
'handlers=stderr',
'qualname=boto'
],
'logger_suds' =>
[
'level=INFO',
'handlers=stderr',
'qualname=suds'
],
'logger_eventletwsgi' =>
[
'level=WARNING',
'handlers=stderr',
'qualname=eventlet.wsgi.server'
],
'logger_nova_api_openstack_wsgi' =>
[
'level=WARNING',
'handlers=prod,debug',
'qualname=nova.api.openstack.wsgi'
],
'logger_nova_osapi_compute_wsgi_server' =>
[
'level=WARNING',
'handlers=prod,debug',
'qualname=nova.osapi_compute.wsgi.server'
]
}.each do |section, content|
content.each do |line|
expect(chef_run).to render_config_file(file.name).with_section_content(section, line)
end
end
end
end
context 'formatters' do
it 'adds default formatters' do
[
['[formatters]',
'keys=normal,normal_with_name,debug,syslog_with_name,syslog_debug'],
['[formatter_normal]',
'format=%(asctime)s %(levelname)s %(message)s'],
['[formatter_normal_with_name]',
'format=[%(name)s]: %(asctime)s %(levelname)s %(message)s'],
['[formatter_debug]',
'format=[%(name)s]: %(asctime)s %(levelname)s %(module)s.%(funcName)s %(message)s'],
['[formatter_syslog_with_name]',
'format=%(name)s: %(levelname)s %(message)s'],
['[formatter_syslog_debug]',
'format=%(name)s: %(levelname)s %(module)s.%(funcName)s %(message)s']
].each do |content|
expect(chef_run).to render_file(file.name).with_content(build_section(content))
{
'formatters' =>
'keys=normal,normal_with_name,debug,syslog_with_name,syslog_debug',
'formatter_normal' =>
'format=%(asctime)s %(levelname)s %(message)s',
'formatter_normal_with_name' =>
'format=[%(name)s]: %(asctime)s %(levelname)s %(message)s',
'formatter_debug' =>
'format=[%(name)s]: %(asctime)s %(levelname)s %(module)s.%(funcName)s %(message)s',
'formatter_syslog_with_name' =>
'format=%(name)s: %(levelname)s %(message)s',
'formatter_syslog_debug' =>
'format=%(name)s: %(levelname)s %(module)s.%(funcName)s %(message)s'
}.each do |section, content|
expect(chef_run).to render_config_file(file.name).with_section_content(section, content)
end
end
end
context 'handlers' do
it 'adds default handlers' do
[
['[handlers]',
'keys=stderr,devel,prod,debug'],
['[handler_stderr]',
'args=(sys.stderr,)',
'class=StreamHandler',
'formatter=debug'],
['[handler_devel]',
'args=(sys.stdout,)',
'class=StreamHandler',
'formatter=debug',
'level=NOTSET'],
['[handler_prod]',
"args=(('/dev/log'), handlers.SysLogHandler.LOG_LOCAL0)",
'class=handlers.SysLogHandler',
'formatter=syslog_with_name',
'level=INFO'],
['[handler_debug]',
"args=(('/dev/log'), handlers.SysLogHandler.LOG_LOCAL1)",
'class=handlers.SysLogHandler',
'formatter=syslog_debug',
'level=DEBUG']
].each do |content|
expect(chef_run).to render_file(file.name).with_content(build_section(content))
{
'handlers' =>
['keys=stderr,devel,prod,debug'],
'handler_stderr' =>
[
'args=(sys.stderr,)',
'class=StreamHandler',
'formatter=debug'
],
'handler_devel' =>
[
'args=(sys.stdout,)',
'class=StreamHandler',
'formatter=debug',
'level=NOTSET'
],
'handler_prod' =>
[
"args=(('/dev/log'), handlers.SysLogHandler.LOG_LOCAL0)",
'class=handlers.SysLogHandler',
'formatter=syslog_with_name',
'level=INFO'
],
'handler_debug' =>
[
"args=(('/dev/log'), handlers.SysLogHandler.LOG_LOCAL1)",
'class=handlers.SysLogHandler',
'formatter=syslog_debug',
'level=DEBUG'
]
}.each do |section, content|
content.each do |line|
expect(chef_run).to render_config_file(file.name).with_section_content(section, line)
end
end
end
end

View File

@ -23,12 +23,6 @@ SUSE_OPTS = {
# We set a default platform for non-platform specific test cases
CHEFSPEC_OPTS = UBUNTU_OPTS
# Build a regex for a section of lines
def build_section(lines)
lines.map! { |line| Regexp.quote(line) }
/^#{lines.join('\n')}/
end
shared_context 'library-stubs' do
before do
allow(subject).to receive(:node).and_return(chef_run.node)