2015-07-14 22:50:34 +00:00
# copyright: 2015, Vulcano Security GmbH
2019-08-20 22:47:11 +00:00
require " rspec/matchers "
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
2019-06-11 22:24:35 +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
2019-06-11 22:24:35 +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
2019-06-11 22:24:35 +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
2015-07-15 13:16:28 +00:00
RSpec :: Matchers . define :contain_duplicates do
match do | arr |
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
2017-02-08 22:49:16 +00:00
raise " [UNSUPPORTED] Please use the new resources 'gem', 'npm' or 'pip'. "
2015-09-08 22:10:54 +00:00
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 |
2019-06-11 22:24:35 +00:00
raise " [UNSUPPORTED] with level is not supported "
2015-09-14 13:01:33 +00:00
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 |
2019-06-11 22:24:35 +00:00
raise " [UNSUPPORTED] under is not supported "
2015-09-14 13:01:33 +00:00
end
failure_message do | service |
" expected that ` #{ service } ` is running "
end
end
2015-10-03 11:32:19 +00:00
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 |
2019-06-11 22:24:35 +00:00
raise " [UNSUPPORTED] `with` is not supported in combination with `be_reachable` "
2015-10-09 17:10:10 +00:00
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 |
2017-02-08 22:49:16 +00:00
raise " [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
2019-06-23 00:35:32 +00:00
# matcher for iptables and ip6tables
2015-10-11 22:21:11 +00:00
RSpec :: Matchers . define :have_rule do | rule |
match do | tables |
tables . has_rule? ( rule )
end
chain :with_table do | _table |
2017-02-08 22:49:16 +00:00
raise " [UNSUPPORTED] `with_table` is not supported in combination with `have_rule`. Please use the following syntax `iptables(table:'mangle', chain: 'input')`. "
2015-10-11 22:21:11 +00:00
end
chain :with_chain do | _chain |
2017-02-08 22:49:16 +00:00
raise " [UNSUPPORTED] `with_table` is not supported in combination with `with_chain`. Please use the following syntax `iptables(table:'mangle', chain: 'input')`. "
2015-10-11 22:21:11 +00:00
end
end
2015-10-23 21:24:00 +00:00
2017-08-07 14:05:22 +00:00
# `be_in` matcher
# You can use it in the following cases:
# - check if an item or array is included in a given array
# eg:
# describe nginx do
# its('user') { should be_in AUTHORIZED_USER_LIST }
# end
# describe nginx do
# its('module_list') { should be_in AUTHORIZED_MODULE_LIST }
# end
RSpec :: Matchers . define :be_in do | list |
match do | item |
# Handle both single item and array
item . is_a? ( Array ) ? ( item - list ) . empty? : list . include? ( item )
end
match_when_negated do | item |
# Handle both single item and array
item . is_a? ( Array ) ? ( item & list ) . empty? : ! list . include? ( item )
end
failure_message do | item |
if item . is_a? ( Array )
" expected ` #{ item } ` to be in the list: ` #{ list } ` \n Diff: \n #{ ( item - list ) } "
else
" expected ` #{ item } ` to be in the list: ` #{ list } ` "
end
end
failure_message_when_negated do | item |
if item . is_a? ( Array )
" expected ` #{ item } ` not to be in the list: ` #{ list } ` \n Comm: \n #{ ( item & list ) } "
else
" expected ` #{ item } ` not to be in the list: ` #{ list } ` "
end
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)
#
2017-11-21 07:49:41 +00:00
RSpec :: Matchers . define :cmp do | first_expected | # rubocop:disable Metrics/BlockLength
2015-12-11 16:02:48 +00:00
def integer? ( value )
2018-05-02 14:19:57 +00:00
! ( value =~ / \ A-?0+ \ 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
2019-05-02 00:52:10 +00:00
rescue ArgumentError , TypeError
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 )
2019-07-09 00:20:30 +00:00
2019-05-02 00:52:10 +00:00
! ( value =~ / \ A0+[0-7]+ \ 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
2016-12-15 04:45:38 +00:00
def version? ( value )
Gem :: Version . new ( value )
true
rescue ArgumentError = > _ex
false
end
2016-06-18 18:33:08 +00:00
# expects that the values have been checked with boolean?
def to_boolean ( value )
2019-06-11 22:24:35 +00:00
value . casecmp ( " true " ) == 0
2016-06-18 18:33:08 +00:00
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 == :==
2019-05-01 22:30:53 +00:00
return Gem :: Version . new ( actual ) . send ( op , Gem :: Version . new ( expected ) ) if
2016-12-15 04:45:38 +00:00
version? ( expected ) && version? ( actual )
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 )
2019-05-01 22:30:53 +00:00
return actual . send ( op , expected . to_i )
2016-06-18 18:33:08 +00:00
elsif expected . is_a? ( String ) && boolean? ( expected ) && [ true , false ] . include? ( actual )
2019-05-01 22:30:53 +00:00
return actual . send ( op , to_boolean ( expected ) )
2019-11-23 00:16:16 +00:00
elsif expected . is_a? ( Integer ) && actual . is_a? ( String ) && integer? ( actual )
2019-05-01 22:30:53 +00:00
return actual . to_i . send ( op , expected )
2015-12-11 16:02:48 +00:00
elsif expected . is_a? ( Float ) && float? ( actual )
2019-05-01 22:30:53 +00:00
return actual . to_f . send ( op , expected )
2017-10-07 10:28:07 +00:00
elsif actual . is_a? ( Symbol ) && expected . is_a? ( String )
2019-05-02 00:52:10 +00:00
return try_match ( actual . to_s , op , expected )
2015-12-16 10:32:31 +00:00
elsif octal? ( expected ) && actual . is_a? ( Integer )
2019-05-01 22:30:53 +00:00
return actual . send ( op , expected . to_i ( 8 ) )
2016-04-15 13:11:45 +00:00
end
# fallback to simple operation
2019-05-01 22:30:53 +00:00
actual . send ( op , expected )
2016-04-15 13:11:45 +00:00
rescue NameError = > _
false
rescue ArgumentError
false
end
match do | actual |
@operation || = :==
@expected || = first_expected
return actual === @expected if @operation == :=== # rubocop:disable Style/CaseEquality
2019-07-09 00:20:30 +00:00
2016-04-15 13:11:45 +00:00
actual = actual [ 0 ] if actual . is_a? ( Array ) && ! @expected . is_a? ( Array ) && actual . length == 1
try_match ( actual , @operation , @expected )
end
2019-07-09 00:20:30 +00:00
% i { == != < < = > = > === =~ } . 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 )
2019-06-11 22:24:35 +00:00
return " expected: " + @expected . inspect if @operation == :== && ! negate
2019-07-09 00:20:30 +00:00
2019-06-11 22:24:35 +00:00
negate_str = negate ? " not " : " "
2016-04-20 02:10:39 +00:00
" expected it #{ negate_str } to be #{ @operation } #{ @expected . inspect } "
end
2015-12-11 16:02:48 +00:00
failure_message do | actual |
2019-06-11 22:24:35 +00:00
actual = ( " 0 " + actual . to_s ( 8 ) ) if octal? ( @expected )
2018-10-02 19:27:48 +00:00
" \n " + format_expectation ( false ) + " \n got: #{ actual . inspect } \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 |
2019-06-11 22:24:35 +00:00
actual = ( " 0 " + actual . to_s ( 8 ) ) . inspect if octal? ( @expected )
2018-10-02 19:27:48 +00:00
" \n " + format_expectation ( true ) + " \n got: #{ actual . inspect } \n \n (compared using `cmp` matcher) \n "
2015-12-11 16:02:48 +00:00
end
2016-10-05 18:48:39 +00:00
description do
" cmp #{ @operation } #{ @expected . inspect } "
end
2015-12-11 16:02:48 +00:00
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