2015-07-14 22:50:34 +00:00
# encoding: utf-8
# copyright: 2015, Vulcano Security GmbH
2015-10-06 16:55:44 +00:00
# author: Dominik Richter
# author: Christoph Hartmann
2015-07-14 22:50:34 +00:00
# license: All rights reserved
2015-06-21 09:06:39 +00:00
RSpec :: Matchers . define :be_readable do
match do | file |
2015-10-25 20:33:36 +00:00
file . readable? ( @by , @by_user )
2015-06-21 09:06:39 +00:00
end
2015-10-25 20:33:36 +00:00
chain :by do | by |
@by = by
2015-06-21 09:06:39 +00:00
end
chain :by_user do | by_user |
@by_user = by_user
end
description do
2015-09-03 18:35:23 +00:00
res = 'be readable'
2015-10-25 20:33:36 +00:00
res += " by #{ @by } " unless @by . nil?
2015-06-21 09:06:39 +00:00
res += " by user #{ @by_user } " unless @by_user . nil?
res
end
end
RSpec :: Matchers . define :be_writable do
match do | file |
2015-10-25 20:33:36 +00:00
file . writable? ( @by , @by_user )
2015-06-21 09:06:39 +00:00
end
2015-10-25 20:33:36 +00:00
chain :by do | by |
@by = by
2015-06-21 09:06:39 +00:00
end
chain :by_user do | by_user |
@by_user = by_user
end
description do
2015-09-03 18:35:23 +00:00
res = 'be writable'
2015-10-25 20:33:36 +00:00
res += " by #{ @by } " unless @by . nil?
2015-06-21 09:06:39 +00:00
res += " by user #{ @by_user } " unless @by_user . nil?
res
end
end
RSpec :: Matchers . define :be_executable do
match do | file |
2015-10-25 20:33:36 +00:00
file . executable? ( @by , @by_user )
2015-06-21 09:06:39 +00:00
end
2015-10-25 20:33:36 +00:00
chain :by do | by |
@by = by
2015-06-21 09:06:39 +00:00
end
chain :by_user do | by_user |
@by_user = by_user
end
description do
2015-09-03 18:35:23 +00:00
res = 'be executable'
2015-10-25 20:33:36 +00:00
res += " by #{ @by } " unless @by . nil?
2015-06-21 09:06:39 +00:00
res += " by user #{ @by_user } " unless @by_user . nil?
res
end
end
2015-07-14 22:50:34 +00:00
# matcher to check /etc/passwd, /etc/shadow and /etc/group
RSpec :: Matchers . define :contain_legacy_plus do
match do | file |
2016-05-11 12:58:18 +00:00
warn '[DEPRECATION] `contain_legacy_plus` is deprecated and will be removed for InSpec 1.0. Please use `describe file(\'/etc/passwd\') do its(\'content\') { should_not match /^\+:/ } end`'
2016-01-15 02:59:00 +00:00
file . content =~ / ^ \ +: /
2015-07-14 22:50:34 +00:00
end
end
# verifies that no entry in an array contains a value
RSpec :: Matchers . define :contain_match do | regex |
match do | arr |
2016-05-11 12:58:18 +00:00
warn '[DEPRECATION] `contain_match` is deprecated and will be removed for InSpec 1.0. See https://github.com/chef/inspec/issues/738 for more details'
2016-05-11 12:42:23 +00:00
arr . inject { | result , i |
result = i . match ( regex )
result || i . match ( / $ / )
}
2015-07-14 22:50:34 +00:00
end
end
2015-07-15 13:16:28 +00:00
RSpec :: Matchers . define :contain_duplicates do
match do | arr |
2016-05-11 12:58:18 +00:00
warn '[DEPRECATION] `contain_duplicates` is deprecated and will be removed for InSpec 1.0. See https://github.com/chef/inspec/issues/738 for more details'
2016-05-11 12:42:23 +00:00
dup = arr . select { | element | arr . count ( element ) > 1 }
2015-07-15 13:16:28 +00:00
! dup . uniq . empty?
end
end
2015-09-08 22:10:54 +00:00
# for packages
RSpec :: Matchers . define :be_installed do
match do | package |
package . installed? == true
end
failure_message do | package |
" expected that ` #{ package } ` is installed "
end
chain :by do
fail " [UNSUPPORTED] Please use the new resources 'gem', 'npm' or 'pip'. "
end
chain :with_version do | version |
2016-05-03 22:14:33 +00:00
warn " [DEPRECATION] `with_version` is deprecated. Please use `its('version') { should eq '1.4.1' }` instead. "
2015-09-08 22:10:54 +00:00
@version = version
end
end
2015-09-14 13:01:33 +00:00
# for services
RSpec :: Matchers . define :be_enabled do
match do | service |
service . enabled? == true
end
chain :with_level do | _level |
fail '[UNSUPPORTED] with level is not supported'
end
failure_message do | service |
" expected that ` #{ service } ` is enabled "
end
end
2015-10-03 11:32:19 +00:00
# service resource matcher for serverspec compatibility
# Deprecated: You should not use this matcher anymore
2015-09-14 13:01:33 +00:00
RSpec :: Matchers . define :be_running do
match do | service |
service . running? == true
end
chain :under do | _under |
fail '[UNSUPPORTED] under is not supported'
end
failure_message do | service |
" expected that ` #{ service } ` is running "
end
end
2015-10-03 11:32:19 +00:00
# user resource matcher for serverspec compatibility
# Deprecated: You should not use this matcher anymore
RSpec :: Matchers . define :belong_to_group do | compare_group |
match do | user |
2016-05-03 22:14:33 +00:00
warn " [DEPRECATION] `belong_to_group` is deprecated. Please use `its('groups') { should include('root') }` instead. "
2015-10-03 11:32:19 +00:00
user . groups . include? ( compare_group )
end
failure_message do | group |
" expected that the user belongs to group ` #{ group } ` "
end
end
# user resource matcher for serverspec compatibility
# Deprecated: You should not use this matcher anymore
RSpec :: Matchers . define :belong_to_primary_group do | compare_group |
match do | user |
2016-05-03 22:14:33 +00:00
warn " [DEPRECATION] `belong_to_primary_group` is deprecated. Please use `its('group') { should eq 'root' }` instead. "
2015-10-03 11:32:19 +00:00
user . group == compare_group
end
failure_message do | group |
" expected that the user belongs to primary group ` #{ group } ` "
end
end
2015-10-09 17:10:10 +00:00
# matcher to check if host is reachable
RSpec :: Matchers . define :be_reachable do
match do | host |
host . reachable? == true
end
chain :with do | _attr |
fail '[UNSUPPORTED] `with` is not supported in combination with `be_reachable`'
end
failure_message do | host |
" expected that host #{ host } is reachable "
end
end
# matcher to check if host is resolvable
RSpec :: Matchers . define :be_resolvable do
match do | host |
host . resolvable? == true
end
chain :by do | _type |
2015-10-11 22:21:11 +00:00
fail " [UNSUPPORTED] `by` is not supported in combination with `be_resolvable`. Please use the following syntax `host('example.com', port: 53, proto: 'udp')`. "
2015-10-09 17:10:10 +00:00
end
failure_message do | host |
" expected that host #{ host } is resolvable "
end
end
2015-10-11 22:21:11 +00:00
# matcher for iptables
RSpec :: Matchers . define :have_rule do | rule |
match do | tables |
tables . has_rule? ( rule )
end
chain :with_table do | _table |
fail " [UNSUPPORTED] `with_table` is not supported in combination with `have_rule`. Please use the following syntax `iptables(table:'mangle', chain: 'input')`. "
end
chain :with_chain do | _chain |
fail " [UNSUPPORTED] `with_table` is not supported in combination with `with_chain`. Please use the following syntax `iptables(table:'mangle', chain: 'input')`. "
end
end
2015-10-23 21:24:00 +00:00
# unsupported
RSpec :: Matchers . define :contain do | _rule |
match do | _resource |
fail " [UNSUPPORTED] `contain` matcher. Please use the following syntax `its('content') { should match('value') }`. "
end
end
2015-12-11 16:02:48 +00:00
# This matcher implements a compare feature that cannot be covered by the default
# `eq` matcher
# You can use it in the following cases:
# - compare strings case-insensitive
# - you expect a number (strings will be converted if possible)
#
2016-04-15 13:11:45 +00:00
RSpec :: Matchers . define :cmp do | first_expected |
2015-12-11 16:02:48 +00:00
def integer? ( value )
2016-08-29 23:39:39 +00:00
! ( value =~ / \ A0+ \ Z| \ A[1-9] \ d* \ Z / ) . nil?
2015-12-11 16:02:48 +00:00
end
def float? ( value )
2016-02-18 11:07:40 +00:00
Float ( value )
true
2015-12-11 16:48:05 +00:00
rescue ArgumentError = > _ex
2015-12-11 16:26:46 +00:00
false
2015-12-11 16:02:48 +00:00
end
2015-12-16 10:32:31 +00:00
def octal? ( value )
2016-04-20 02:09:05 +00:00
return false unless value . is_a? ( String )
2016-02-18 11:07:40 +00:00
! ( value =~ / \ A0+ \ d+ \ Z / ) . nil?
2015-12-16 10:32:31 +00:00
end
2016-06-18 18:33:08 +00:00
def boolean? ( value )
%w{ true false } . include? ( value . downcase )
end
# expects that the values have been checked with boolean?
def to_boolean ( value )
value . casecmp ( 'true' ) == 0
end
2016-04-20 02:09:05 +00:00
def try_match ( actual , op , expected ) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
2015-12-11 16:02:48 +00:00
# if actual and expected are strings
2015-12-16 10:32:31 +00:00
if expected . is_a? ( String ) && actual . is_a? ( String )
2016-04-15 13:11:45 +00:00
return actual . casecmp ( expected ) == 0 if op == :==
2016-04-20 09:34:07 +00:00
elsif expected . is_a? ( Regexp ) && ( actual . is_a? ( String ) || actual . is_a? ( Integer ) )
return ! actual . to_s . match ( expected ) . nil?
2016-02-23 21:18:16 +00:00
elsif expected . is_a? ( String ) && integer? ( expected ) && actual . is_a? ( Integer )
2016-04-15 13:11:45 +00:00
return actual . method ( op ) . call ( expected . to_i )
2016-06-18 18:33:08 +00:00
elsif expected . is_a? ( String ) && boolean? ( expected ) && [ true , false ] . include? ( actual )
return actual . method ( op ) . call ( to_boolean ( expected ) )
2015-12-11 16:02:48 +00:00
elsif expected . is_a? ( Integer ) && integer? ( actual )
2016-04-15 13:11:45 +00:00
return actual . to_i . method ( op ) . call ( expected )
2015-12-11 16:02:48 +00:00
elsif expected . is_a? ( Float ) && float? ( actual )
2016-04-15 13:11:45 +00:00
return actual . to_f . method ( op ) . call ( expected )
2015-12-16 10:32:31 +00:00
elsif octal? ( expected ) && actual . is_a? ( Integer )
2016-04-15 13:11:45 +00:00
return actual . method ( op ) . call ( expected . to_i ( 8 ) )
end
# fallback to simple operation
actual . method ( op ) . call ( expected )
rescue NameError = > _
false
rescue ArgumentError
false
end
match do | actual |
@operation || = :==
@expected || = first_expected
return actual === @expected if @operation == :=== # rubocop:disable Style/CaseEquality
actual = actual [ 0 ] if actual . is_a? ( Array ) && ! @expected . is_a? ( Array ) && actual . length == 1
try_match ( actual , @operation , @expected )
end
2016-04-20 02:10:39 +00:00
[ :== , :'!=' , :< , :< = , :>= , :> , :=== , : =~ ] . each do | op |
2016-04-15 13:11:45 +00:00
chain ( op ) do | x |
@operation = op
@expected = x
2015-12-11 16:02:48 +00:00
end
end
2016-04-20 02:10:39 +00:00
def format_expectation ( negate )
return 'expected: ' + @expected . inspect if @operation == :== && ! negate
negate_str = negate ? 'not ' : ''
" expected it #{ negate_str } to be #{ @operation } #{ @expected . inspect } "
end
2015-12-11 16:02:48 +00:00
failure_message do | actual |
2016-04-17 22:50:21 +00:00
actual = '0' + actual . to_s ( 8 ) if octal? ( @expected )
2016-04-20 02:10:39 +00:00
" \n " + format_expectation ( false ) + " \n got: #{ actual } \n \n (compared using `cmp` matcher) \n "
2015-12-11 16:02:48 +00:00
end
2015-12-11 16:17:01 +00:00
failure_message_when_negated do | actual |
2016-04-17 22:50:21 +00:00
actual = '0' + actual . to_s ( 8 ) if octal? ( @expected )
2016-04-20 02:10:39 +00:00
" \n " + format_expectation ( true ) + " \n got: #{ actual } \n \n (compared using `cmp` matcher) \n "
2015-12-11 16:02:48 +00:00
end
end
2015-12-31 00:08:57 +00:00
# user resource matcher for serverspec compatibility
# This matcher will be deprecated in future
RSpec :: Matchers . define :be_mounted do
match do | path |
if ! @options . nil?
path . mounted? ( @options , @identical )
else
path . mounted?
end
end
chain :with do | attr |
@options = attr
@identical = false
end
chain :only_with do | attr |
@options = attr
@identical = true
end
failure_message do | path |
if ! @options . nil?
" \n #{ path } is not mounted with the options \n expected: #{ @options } \n got: #{ path . mount_options } \n "
else
" \n #{ path } is not mounted \n "
end
end
end