chef-attribute-validator 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/CHANGES +4 -0
- data/Gemfile +3 -1
- data/README.md +15 -11
- data/Rakefile +12 -2
- data/lib/chef-attribute-validator/attribute_set.rb +7 -61
- data/lib/chef-attribute-validator/version.rb +1 -1
- data/lib/chef-attribute-validator/wildcard_expander/brutal_regex.rb +76 -0
- data/lib/chef-attribute-validator/wildcard_expander/no_wildcards.rb +29 -0
- data/lib/chef-attribute-validator/wildcard_expander.rb +103 -0
- data/test/fixtures/expander_brutal_deep_hash.rb +5 -0
- data/test/fixtures/expander_brutal_deep_mixed.rb +5 -0
- data/test/fixtures/expander_brutal_flat.rb +4 -0
- data/test/unit/attr_set_spec.rb +58 -0
- data/test/unit/attr_set_spec_wildcard.rb +114 -0
- data/test/unit/expanders/brutal_regex_spec.rb +132 -0
- metadata +19 -4
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MThmOWZjYmNhMzI0ODZiODM4ZmNmMWYzOGVkYjNjZDIyMWMzZGU0OA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZWU3YmQzMGNkYmQ2Y2ExYTE1NWQ4MWY1MmUzNDVhMTljNjAzNDE0MA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ZDFiZjFiNmUyZDE2MTljOTI3ZWNiNDI5ZjVjN2ZmNTAyYTVhMDdiMzMwZmU1
|
10
|
+
MGZmODUxZDIyNjJhNjJhMmMzODYzMjMwZWFkMDIyNzg3YWU5YWZkYjQ1Mjg3
|
11
|
+
YzU5YTJiNjM3NDM0Y2EwM2FlYjdmMGZmNjEzMzU3M2FiYTU2OGI=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MmVmZWQ1YzA2M2ZlOTkxMjE2ZDg5ZGE0MmI0NGRkZTcwNDQ3M2I5YWRhYTdk
|
14
|
+
OTY3N2E3ZjZhN2I4NTk5YTc2NjBlYjk5ZDViMWI5M2U3NDM4M2NjYjlmNTNi
|
15
|
+
NTdjNzJmMzI4MWM5NDNjYWQ0ZmU3MGZmYWU5NmRjY2ZlYmQ0YjU=
|
data/CHANGES
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -68,13 +68,13 @@ Given:
|
|
68
68
|
|
69
69
|
## Bugs, Limitations and Roadmap
|
70
70
|
|
71
|
-
|
71
|
+
### How to Report Bugs
|
72
72
|
|
73
|
-
|
73
|
+
Open a github issue at https://github.com/clintoncwolfe/chef-attribute-validator, ideally with a failing test case, a pull request that fixes the bug, and a unicorn.
|
74
74
|
|
75
|
-
|
76
|
-
|
77
|
-
|
75
|
+
### Roadmap
|
76
|
+
|
77
|
+
#### Some wildcard syntax not yet supported
|
78
78
|
|
79
79
|
Possibly eventually support for **, [<charclass>], or {<alternatives>}.
|
80
80
|
|
@@ -82,18 +82,22 @@ Possibly eventually support for **, [<charclass>], or {<alternatives>}.
|
|
82
82
|
|
83
83
|
Simple cookbook named 'attribute-validator' that loads the gem and provides recipes for compile-time and convergence-time violation checking.
|
84
84
|
|
85
|
-
|
86
|
-
|
87
|
-
No real exception class, just raising a bare string exception, which could certainly be improved upon.
|
88
|
-
|
89
|
-
### Planned checks:
|
85
|
+
#### Planned checks:
|
90
86
|
|
91
87
|
looks_like/hostname
|
92
88
|
looks_like/email
|
93
89
|
name_regex - Regexp. Applies given regex to the last element in the attribute path ('basename', if you will)
|
94
90
|
present - Boolean. If true, fails if the path matches zero attributes. If false, fails if the path matches nonzero attributes. Does not consider nilness, only existence of attribute key(s). See also required.
|
95
91
|
|
96
|
-
|
92
|
+
### Bugs and Defects
|
93
|
+
|
94
|
+
#### Lame Exceptions
|
95
|
+
|
96
|
+
No real exception class, just raising a bare string exception, which could certainly be improved upon; hard to catch.
|
97
|
+
|
98
|
+
#### Wildcard Expander implementation is simplistic and inefficient
|
99
|
+
|
100
|
+
BrutalRegex is terrible.
|
97
101
|
|
98
102
|
|
99
103
|
## Author
|
data/Rakefile
CHANGED
@@ -11,13 +11,23 @@ task :test
|
|
11
11
|
task :test => [:syntax]
|
12
12
|
desc "Checks ruby files for syntax errors"
|
13
13
|
task :syntax do |t|
|
14
|
+
puts "------------Syntax-----------"
|
14
15
|
Dir.glob('**/*.rb').each do |f|
|
15
16
|
system("/bin/echo -n '#{f}: '; ruby -c #{f}")
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
19
|
-
|
20
|
-
|
20
|
+
|
21
|
+
task :test => [:rubocop]
|
22
|
+
desc "Runs rubocop against the code, to enforce style and standards."
|
23
|
+
task :rubocop do |t|
|
24
|
+
puts "------------Rubocop-----------"
|
25
|
+
system("rubocop -c rubocop.yml")
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
#task :test => [:unit]
|
30
|
+
#desc "Runs unit tests"
|
21
31
|
#RSpec::Core::RakeTask.new(:unit) do |t|
|
22
32
|
# t.pattern = 'test/unit/**/*_spec.rb'
|
23
33
|
# t.rspec_opts = "-fd"
|
@@ -1,6 +1,8 @@
|
|
1
1
|
|
2
2
|
require 'forwardable'
|
3
3
|
|
4
|
+
require_relative './wildcard_expander'
|
5
|
+
|
4
6
|
class Chef
|
5
7
|
class Attribute
|
6
8
|
class Validator
|
@@ -19,71 +21,15 @@ class Chef
|
|
19
21
|
@path = a_path
|
20
22
|
@node = a_node
|
21
23
|
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def embowel
|
28
|
-
# Split on /
|
29
|
-
steps = path.split('/')
|
30
|
-
|
31
|
-
# Since we begin with /, the first element is ""
|
32
|
-
if steps[0] == "" then steps.shift end
|
33
|
-
|
34
|
-
# Promote integer strings to integers
|
35
|
-
steps.map! { |s| s.match(/^\d+$/) ? s.to_i : s }
|
36
|
-
|
37
|
-
# TODO: some ckine of wildcard expansion
|
38
|
-
all_steps = [ steps ]
|
39
|
-
|
40
|
-
all_steps.each do |these_steps|
|
41
|
-
if path_exists_by_steps?(these_steps) then
|
42
|
-
guts['/' + these_steps.join('/')] = fetch_val_by_steps(these_steps)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def path_exists_by_steps? (the_steps)
|
48
|
-
nv = node
|
49
|
-
steps = the_steps.dup
|
50
|
-
while steps.size > 0
|
51
|
-
step = steps.shift
|
52
|
-
|
53
|
-
# binding.pry
|
54
|
-
if nv.kind_of?(Chef::Node::ImmutableArray) then
|
55
|
-
# TODO: what if the step isn't an int?
|
24
|
+
expander = Chef::Attribute::Validator::WildcardExpander.choose(path, node)
|
56
25
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
return false
|
62
|
-
end
|
63
|
-
|
64
|
-
elsif nv.respond_to?(:has_key?) then
|
65
|
-
if nv.has_key?(step) then
|
66
|
-
nv = nv[step]
|
67
|
-
else
|
68
|
-
# No such key
|
69
|
-
return false
|
70
|
-
end
|
71
|
-
else
|
72
|
-
# Must be a scalar?
|
73
|
-
return false
|
74
|
-
end
|
26
|
+
# TODO: less dumb thing would be to have wildcard expander just be an enumerator
|
27
|
+
# and then call it on each access
|
28
|
+
expander.expand_all.each do | slashpath |
|
29
|
+
guts[slashpath] = expander.fetch_val_by_slashpath(slashpath)
|
75
30
|
end
|
76
|
-
return true
|
77
31
|
end
|
78
32
|
|
79
|
-
def fetch_val_by_steps(the_steps)
|
80
|
-
nv = node
|
81
|
-
steps = the_steps.dup
|
82
|
-
while steps.size > 0
|
83
|
-
nv = nv[steps.shift]
|
84
|
-
end
|
85
|
-
nv
|
86
|
-
end
|
87
33
|
end
|
88
34
|
end
|
89
35
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
class Chef
|
2
|
+
class Attribute
|
3
|
+
class Validator
|
4
|
+
class WildcardExpander
|
5
|
+
class BrutalRegex < WildcardExpander
|
6
|
+
|
7
|
+
register(self)
|
8
|
+
|
9
|
+
def expand_all
|
10
|
+
# Create a massive list of all attribute paths, in slashpath format
|
11
|
+
all_slashpaths = find_all_slashpaths
|
12
|
+
|
13
|
+
# Convert the path_spec into a terrifying regex
|
14
|
+
regex_spec = convert_path_spec_to_regex
|
15
|
+
|
16
|
+
# Filter the list by grepping
|
17
|
+
all_slashpaths.grep(regex_spec)
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
def suitability
|
22
|
+
# I can do anything, but I'll do it badly
|
23
|
+
0.1
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
# TODO: maybe we could cache this on the node, or something?
|
28
|
+
def find_all_slashpaths (prefix='', node_cursor = nil)
|
29
|
+
node_cursor ||= node
|
30
|
+
child_paths = []
|
31
|
+
|
32
|
+
|
33
|
+
if node_cursor.kind_of?(Array)
|
34
|
+
node_cursor.each_index do |idx|
|
35
|
+
child_paths.push prefix + '/' + idx.to_s
|
36
|
+
if node_cursor[idx].kind_of?(Mash) || node_cursor[idx].kind_of?(Array)
|
37
|
+
child_paths += find_all_slashpaths(prefix + '/' + idx.to_s, node_cursor[idx])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
else
|
41
|
+
node_cursor.keys.each do |key|
|
42
|
+
child_paths.push prefix + '/' + key
|
43
|
+
if node_cursor[key].kind_of?(Mash) || node_cursor[key].kind_of?(Array)
|
44
|
+
child_paths += find_all_slashpaths(prefix + '/' + key, node_cursor[key])
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
child_paths
|
49
|
+
end
|
50
|
+
|
51
|
+
def convert_path_spec_to_regex
|
52
|
+
re = path_spec.dup
|
53
|
+
|
54
|
+
# Anchor everything
|
55
|
+
re = '^' + re + '$'
|
56
|
+
|
57
|
+
# * => "anything but a slash"
|
58
|
+
re.gsub!(/([^*])\*(?!\*)/, '\1[^\/]*')
|
59
|
+
|
60
|
+
# ? => "any single char other than a slash"
|
61
|
+
re.gsub!(/\?/, '[^\/]')
|
62
|
+
|
63
|
+
# ** => "anything"
|
64
|
+
re.gsub!(/\*\*/, '.*')
|
65
|
+
|
66
|
+
# {,} => alternatives # TODO
|
67
|
+
|
68
|
+
Regexp.new(re)
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Chef
|
2
|
+
class Attribute
|
3
|
+
class Validator
|
4
|
+
class WildcardExpander
|
5
|
+
class NoWildcards < WildcardExpander
|
6
|
+
|
7
|
+
register(self)
|
8
|
+
|
9
|
+
def expand_all
|
10
|
+
if path_exists_by_slashpath?(path_spec)
|
11
|
+
[ path_spec ]
|
12
|
+
else
|
13
|
+
[ ]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def suitability
|
18
|
+
if path_contains_wildcards?(path_spec)
|
19
|
+
0.0
|
20
|
+
else
|
21
|
+
1.0
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
class Chef
|
2
|
+
class Attribute
|
3
|
+
class Validator
|
4
|
+
class WildcardExpander
|
5
|
+
|
6
|
+
|
7
|
+
attr_accessor :path_spec
|
8
|
+
attr_accessor :node
|
9
|
+
|
10
|
+
def initialize(a_path_spec, a_node)
|
11
|
+
@path_spec = a_path_spec
|
12
|
+
@node = a_node
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.choose(path_spec, node)
|
16
|
+
# Ruby is an excellent language in which to write Perl
|
17
|
+
@@subclasses.map {|k| k.new(path_spec, node) }.map {|e| [e, e.suitability]}.sort { |a,b| b[1] <=> a[1] }.map {|e| e[0]}.first
|
18
|
+
end
|
19
|
+
|
20
|
+
def slashpath_to_steps(slashpath)
|
21
|
+
steps = slashpath.split('/')
|
22
|
+
|
23
|
+
# Since we begin with /, the first element is ""
|
24
|
+
if steps[0] == "" then steps.shift end
|
25
|
+
|
26
|
+
# Promote integer strings to integers
|
27
|
+
steps.map! { |s| s.match(/^\d+$/) ? s.to_i : s }
|
28
|
+
|
29
|
+
steps
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
# Note: does not handle missing values correctly!
|
34
|
+
def fetch_val_by_slashpath(slashpath)
|
35
|
+
nv = node
|
36
|
+
steps = slashpath_to_steps(slashpath)
|
37
|
+
while steps.size > 0
|
38
|
+
nv = nv[steps.shift]
|
39
|
+
end
|
40
|
+
nv
|
41
|
+
end
|
42
|
+
|
43
|
+
def path_exists_by_slashpath? (slashpath)
|
44
|
+
nv = node
|
45
|
+
steps = slashpath_to_steps(slashpath)
|
46
|
+
while steps.size > 0
|
47
|
+
step = steps.shift
|
48
|
+
|
49
|
+
if nv.kind_of?(Chef::Node::ImmutableArray) then
|
50
|
+
# TODO: what if the step isn't an int?
|
51
|
+
|
52
|
+
if nv.size > step then
|
53
|
+
nv = nv[step]
|
54
|
+
else
|
55
|
+
# Array not long enough
|
56
|
+
return false
|
57
|
+
end
|
58
|
+
|
59
|
+
elsif nv.respond_to?(:has_key?) then
|
60
|
+
if nv.has_key?(step) then
|
61
|
+
nv = nv[step]
|
62
|
+
else
|
63
|
+
# No such key
|
64
|
+
return false
|
65
|
+
end
|
66
|
+
else
|
67
|
+
# Must be a scalar?
|
68
|
+
return false
|
69
|
+
end
|
70
|
+
end
|
71
|
+
return true
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
def path_contains_wildcards?(path)
|
76
|
+
[
|
77
|
+
/\*/,
|
78
|
+
/\*\*/,
|
79
|
+
/\?/,
|
80
|
+
/\[\w+\]/,
|
81
|
+
/\{\w+(\s*,\s*\w+)?\}/,
|
82
|
+
].any? { |r| r.match(path) }
|
83
|
+
end
|
84
|
+
|
85
|
+
protected
|
86
|
+
|
87
|
+
def suitability
|
88
|
+
0.0
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.register(klass)
|
92
|
+
@@subclasses ||= []
|
93
|
+
@@subclasses.push klass
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
Dir.glob(File.join(File.dirname(__FILE__), 'wildcard_expander', '*.rb')).each do |expander_implementation|
|
102
|
+
require expander_implementation
|
103
|
+
end
|
data/test/unit/attr_set_spec.rb
CHANGED
@@ -52,4 +52,62 @@ describe Chef::Attribute::Validator::AttributeSet do
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
+
describe "basic star wildcard" do
|
56
|
+
|
57
|
+
context "when we are looking at the root element" do
|
58
|
+
it "should be able to run '/*'" do
|
59
|
+
expect { Chef::Attribute::Validator::AttributeSet.new(node, '/*') }.not_to raise_error
|
60
|
+
end
|
61
|
+
let(:ats) { Chef::Attribute::Validator::AttributeSet.new(node, '/*') }
|
62
|
+
it "should be able to list all root elements" do
|
63
|
+
expect(ats.size).to eq 6
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when we use a star at the beginning of a two-step path" do
|
68
|
+
it "should be able to run '/*/one'" do
|
69
|
+
expect { Chef::Attribute::Validator::AttributeSet.new(node, '/*/one') }.not_to raise_error
|
70
|
+
end
|
71
|
+
let(:ats) { Chef::Attribute::Validator::AttributeSet.new(node, '/*/one') }
|
72
|
+
it "should be able to list all '/*/one'" do
|
73
|
+
expect(ats.size).to eq 1
|
74
|
+
expect(ats['/deeper/one']).to eq 1
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context "when we use a star at the end of a two-step path" do
|
79
|
+
it "should be able to run '/deeper/*'" do
|
80
|
+
expect { Chef::Attribute::Validator::AttributeSet.new(node, '/deeper/*') }.not_to raise_error
|
81
|
+
end
|
82
|
+
let(:ats) { Chef::Attribute::Validator::AttributeSet.new(node, '/deeper/*') }
|
83
|
+
it "should be able to list '/deeper/*'" do
|
84
|
+
expect(ats.size).to eq 2
|
85
|
+
expect(ats['/deeper/one']).to eq 1
|
86
|
+
expect(ats['/deeper/deeper_yet']).to be_a_kind_of(Mash)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "when we use a star at the middle of a three-step path" do
|
91
|
+
it "should be able to run '/deeper/*/one'" do
|
92
|
+
expect { Chef::Attribute::Validator::AttributeSet.new(node, '/deeper/*/one') }.not_to raise_error
|
93
|
+
end
|
94
|
+
let(:ats) { Chef::Attribute::Validator::AttributeSet.new(node, '/deeper/*/one') }
|
95
|
+
it "should be able to list '/deeper/*/one" do
|
96
|
+
expect(ats.size).to eq 1
|
97
|
+
expect(ats['/deeper/deeper_yet/one']).to eq 1
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context "when the wildcarded step does not exist" do
|
102
|
+
it "should be able to run '/nope/*'" do
|
103
|
+
expect { Chef::Attribute::Validator::AttributeSet.new(node, '/nope/*') }.not_to raise_error
|
104
|
+
end
|
105
|
+
let(:ats) { Chef::Attribute::Validator::AttributeSet.new(node, '/nope/*') }
|
106
|
+
it "should not be able to find '/nope/*'" do
|
107
|
+
expect(ats.size).to eq 0
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
55
113
|
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require_relative './spec_helper'
|
2
|
+
|
3
|
+
describe Chef::Attribute::Validator::AttributeSet do
|
4
|
+
|
5
|
+
let(:node) { CAVHelper.load_fixture_attributes('attr_set') }
|
6
|
+
|
7
|
+
describe "non-wildcard, non-array slashpath access" do
|
8
|
+
context "when the element exists" do
|
9
|
+
it "should be able to run /one" do
|
10
|
+
expect { Chef::Attribute::Validator::AttributeSet.new(node, '/one') }.not_to raise_error
|
11
|
+
end
|
12
|
+
let(:ats) { Chef::Attribute::Validator::AttributeSet.new(node, '/one') }
|
13
|
+
it "should be able to find /one" do
|
14
|
+
expect(ats.size).to eq 1
|
15
|
+
expect(ats.has_key?('/one')).to be_true
|
16
|
+
expect(ats['/one']).to eq 1
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when the element does not exist" do
|
21
|
+
it "should be able to run /nope" do
|
22
|
+
expect { Chef::Attribute::Validator::AttributeSet.new(node, '/nope') }.not_to raise_error
|
23
|
+
end
|
24
|
+
let(:ats) { Chef::Attribute::Validator::AttributeSet.new(node, '/nope') }
|
25
|
+
it "should not be able to find /nope" do
|
26
|
+
expect(ats.size).to eq 0
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "non-wildcard, array slashpath access" do
|
32
|
+
context "when the element exists" do
|
33
|
+
it "should be able to run /cats/1" do
|
34
|
+
expect { Chef::Attribute::Validator::AttributeSet.new(node, '/cats/1') }.not_to raise_error
|
35
|
+
end
|
36
|
+
let(:ats) { Chef::Attribute::Validator::AttributeSet.new(node, '/cats/1') }
|
37
|
+
it "should be able to find /cats/1" do
|
38
|
+
expect(ats.size).to eq 1
|
39
|
+
expect(ats.has_key?('/cats/1')).to be_true
|
40
|
+
expect(ats['/cats/1']).to eq 'tabby'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when the element does not exist" do
|
45
|
+
it "should be able to run /cats/23" do
|
46
|
+
expect { Chef::Attribute::Validator::AttributeSet.new(node, '/cats/23') }.not_to raise_error
|
47
|
+
end
|
48
|
+
let(:ats) { Chef::Attribute::Validator::AttributeSet.new(node, '/cats/23') }
|
49
|
+
it "should not be able to find /cats/23" do
|
50
|
+
expect(ats.size).to eq 0
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "basic star wildcard" do
|
56
|
+
|
57
|
+
context "when we are looking at the root element" do
|
58
|
+
it "should be able to run '/*'" do
|
59
|
+
expect { Chef::Attribute::Validator::AttributeSet.new(node, '/*') }.not_to raise_error
|
60
|
+
end
|
61
|
+
let(:ats) { Chef::Attribute::Validator::AttributeSet.new(node, '/*') }
|
62
|
+
it "should be able to list all root elements" do
|
63
|
+
expect(ats.size).to eq 7
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when we use a star at the beginning of a two-step path" do
|
68
|
+
it "should be able to run '/*/one'" do
|
69
|
+
expect { Chef::Attribute::Validator::AttributeSet.new(node, '/*/one') }.not_to raise_error
|
70
|
+
end
|
71
|
+
let(:ats) { Chef::Attribute::Validator::AttributeSet.new(node, '/*/one') }
|
72
|
+
it "should be able to list all '/*/one'" do
|
73
|
+
expect(ats.size).to eq 1
|
74
|
+
expect(ats['/deeper/one']).to eq 1
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context "when we use a star at the end of a two-step path" do
|
79
|
+
it "should be able to run '/deeper/*'" do
|
80
|
+
expect { Chef::Attribute::Validator::AttributeSet.new(node, '/deeper/*') }.not_to raise_error
|
81
|
+
end
|
82
|
+
let(:ats) { Chef::Attribute::Validator::AttributeSet.new(node, '/deeper/*') }
|
83
|
+
it "should be able to list '/deeper/*'" do
|
84
|
+
expect(ats.size).to eq 2
|
85
|
+
expect(ats['/deeper/one']).to eq 1
|
86
|
+
expect(ats['/deeper/deeper_yet']).to be_a_kind_of(Mash)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "when we use a star at the middle of a three-step path" do
|
91
|
+
it "should be able to run '/deeper/*/one'" do
|
92
|
+
expect { Chef::Attribute::Validator::AttributeSet.new(node, '/deeper/*/one') }.not_to raise_error
|
93
|
+
end
|
94
|
+
let(:ats) { Chef::Attribute::Validator::AttributeSet.new(node, '/deeper/*/one') }
|
95
|
+
it "should be able to list '/deeper/*/one" do
|
96
|
+
expect(ats.size).to eq 1
|
97
|
+
expect(ats['/deeper/deeper_yet/one']).to eq 1
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context "when the wildcarded step does not exist" do
|
102
|
+
it "should be able to run '/nope/*'" do
|
103
|
+
expect { Chef::Attribute::Validator::AttributeSet.new(node, '/nope/*') }.not_to raise_error
|
104
|
+
end
|
105
|
+
let(:ats) { Chef::Attribute::Validator::AttributeSet.new(node, '/nope/*') }
|
106
|
+
it "should not be able to find '/nope/*'" do
|
107
|
+
expect(ats.size).to eq 0
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe Chef::Attribute::Validator::WildcardExpander::BrutalRegex do
|
4
|
+
|
5
|
+
context "prior to applying filter" do
|
6
|
+
|
7
|
+
context "when examining a shallow node" do
|
8
|
+
let(:node) { CAVHelper.load_fixture_attributes('expander_brutal_flat') }
|
9
|
+
let(:exp) { Chef::Attribute::Validator::WildcardExpander::BrutalRegex.new('/foo', node) }
|
10
|
+
let(:result) { exp.find_all_slashpaths }
|
11
|
+
|
12
|
+
it "should prefix all entries with /" do
|
13
|
+
expect(result.all? { |sp| sp.match(/^\//) }).to be_true
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should find the right number of entries" do
|
17
|
+
expect(result.size).to eql 3
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should find the /foo entry" do
|
21
|
+
expect(result).to include('/foo')
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
context "when examining a deeper node with no arrays" do
|
27
|
+
let(:node) { CAVHelper.load_fixture_attributes('expander_brutal_deep_hash') }
|
28
|
+
let(:exp) { Chef::Attribute::Validator::WildcardExpander::BrutalRegex.new('/foo', node) }
|
29
|
+
let(:result) { exp.find_all_slashpaths }
|
30
|
+
|
31
|
+
|
32
|
+
it "should prefix all entries with /" do
|
33
|
+
expect(result.all? { |sp| sp.match(/^\//) }).to be_true
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should find the right number of entries" do
|
37
|
+
expect(result.size).to eql 7
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should find the /childless entry" do
|
41
|
+
expect(result).to include('/childless')
|
42
|
+
end
|
43
|
+
it "should find the /parent entry" do
|
44
|
+
expect(result).to include('/parent')
|
45
|
+
end
|
46
|
+
it "should find the /parent/child entry" do
|
47
|
+
expect(result).to include('/parent/child')
|
48
|
+
end
|
49
|
+
it "should find the /grandpappy entry" do
|
50
|
+
expect(result).to include('/grandpappy')
|
51
|
+
end
|
52
|
+
it "should find the /grandpappy/parent entry" do
|
53
|
+
expect(result).to include('/grandpappy/parent')
|
54
|
+
end
|
55
|
+
it "should find the /grandpappy/parent/child entry" do
|
56
|
+
expect(result).to include('/grandpappy/parent/child')
|
57
|
+
end
|
58
|
+
it "should find the /empty_hash entry" do
|
59
|
+
expect(result).to include('/empty_hash')
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
context "when examining a deeper node with mixed arrays" do
|
66
|
+
let(:node) { CAVHelper.load_fixture_attributes('expander_brutal_deep_mixed') }
|
67
|
+
let(:exp) { Chef::Attribute::Validator::WildcardExpander::BrutalRegex.new('/foo', node) }
|
68
|
+
let(:result) { exp.find_all_slashpaths }
|
69
|
+
|
70
|
+
|
71
|
+
it "should prefix all entries with /" do
|
72
|
+
expect(result.all? { |sp| sp.match(/^\//) }).to be_true
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should find the right number of entries" do
|
76
|
+
expect(result.size).to eql 11
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should find the /childless entry" do
|
80
|
+
expect(result).to include('/childless')
|
81
|
+
end
|
82
|
+
it "should find the /parent entry" do
|
83
|
+
expect(result).to include('/parent')
|
84
|
+
end
|
85
|
+
it "should find the /parent/0 entry" do
|
86
|
+
expect(result).to include('/parent/0')
|
87
|
+
end
|
88
|
+
it "should find the /parent/1 entry" do
|
89
|
+
expect(result).to include('/parent/1')
|
90
|
+
end
|
91
|
+
it "should find the /empty_array entry" do
|
92
|
+
expect(result).to include('/empty_array')
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should find the /aoh entry" do
|
96
|
+
expect(result).to include('/aoh')
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should find the /aoh/0 entry" do
|
100
|
+
expect(result).to include('/aoh/0')
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should find the /aoh/0/foo entry" do
|
104
|
+
expect(result).to include('/aoh/0/foo')
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context "while converting a pathspec to a regex" do
|
111
|
+
let(:node) { CAVHelper.load_fixture_attributes('expander_brutal_flat') }
|
112
|
+
|
113
|
+
{
|
114
|
+
'/foo' => '^/foo$',
|
115
|
+
'/foo*' => '^/foo[^\/]*$',
|
116
|
+
'/foo*/*/bar' => '^/foo[^\/]*/[^\/]*/bar$',
|
117
|
+
'/?oo' => '^/[^\/]oo$',
|
118
|
+
'/**' => '^/.*$',
|
119
|
+
'/foo/**/bar' => '^/foo/.*/bar$',
|
120
|
+
}.each do | spec, regex |
|
121
|
+
it "should convert '#{spec}' to '#{regex}'" do
|
122
|
+
exp = Chef::Attribute::Validator::WildcardExpander::BrutalRegex.new(spec, node)
|
123
|
+
expect(exp.convert_path_spec_to_regex).to eql Regexp.new(regex)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chef-attribute-validator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Clinton Wolfe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-11-
|
11
|
+
date: 2013-11-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,14 +16,16 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: !binary |-
|
20
|
+
MS4z
|
20
21
|
type: :development
|
21
22
|
prerelease: false
|
22
23
|
version_requirements: !ruby/object:Gem::Requirement
|
23
24
|
requirements:
|
24
25
|
- - ~>
|
25
26
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
27
|
+
version: !binary |-
|
28
|
+
MS4z
|
27
29
|
- !ruby/object:Gem::Dependency
|
28
30
|
name: rake
|
29
31
|
requirement: !ruby/object:Gem::Requirement
|
@@ -81,6 +83,9 @@ files:
|
|
81
83
|
- lib/chef-attribute-validator/rule.rb
|
82
84
|
- lib/chef-attribute-validator/version.rb
|
83
85
|
- lib/chef-attribute-validator/violation.rb
|
86
|
+
- lib/chef-attribute-validator/wildcard_expander.rb
|
87
|
+
- lib/chef-attribute-validator/wildcard_expander/brutal_regex.rb
|
88
|
+
- lib/chef-attribute-validator/wildcard_expander/no_wildcards.rb
|
84
89
|
- test/fixtures/attr_set.rb
|
85
90
|
- test/fixtures/check_child_count.rb
|
86
91
|
- test/fixtures/check_looks_like_arg_ip.rb
|
@@ -99,17 +104,22 @@ files:
|
|
99
104
|
- test/fixtures/check_required_true.rb
|
100
105
|
- test/fixtures/check_required_zero.rb
|
101
106
|
- test/fixtures/check_type.rb
|
107
|
+
- test/fixtures/expander_brutal_deep_hash.rb
|
108
|
+
- test/fixtures/expander_brutal_deep_mixed.rb
|
109
|
+
- test/fixtures/expander_brutal_flat.rb
|
102
110
|
- test/fixtures/rules_empty.rb
|
103
111
|
- test/fixtures/rules_missing_path.rb
|
104
112
|
- test/fixtures/rules_no_check.rb
|
105
113
|
- test/fixtures/rules_type_and_min_children.rb
|
106
114
|
- test/fixtures/rules_type_check.rb
|
107
115
|
- test/unit/attr_set_spec.rb
|
116
|
+
- test/unit/attr_set_spec_wildcard.rb
|
108
117
|
- test/unit/check_child_count_spec.rb
|
109
118
|
- test/unit/check_looks_like_spec.rb
|
110
119
|
- test/unit/check_regex_spec.rb
|
111
120
|
- test/unit/check_required_spec.rb
|
112
121
|
- test/unit/check_type_spec.rb
|
122
|
+
- test/unit/expanders/brutal_regex_spec.rb
|
113
123
|
- test/unit/rule_parse_spec.rb
|
114
124
|
- test/unit/spec_helper.rb
|
115
125
|
homepage: https://github.com/clintoncwolfe/chef-attribute-validator
|
@@ -155,16 +165,21 @@ test_files:
|
|
155
165
|
- test/fixtures/check_required_true.rb
|
156
166
|
- test/fixtures/check_required_zero.rb
|
157
167
|
- test/fixtures/check_type.rb
|
168
|
+
- test/fixtures/expander_brutal_deep_hash.rb
|
169
|
+
- test/fixtures/expander_brutal_deep_mixed.rb
|
170
|
+
- test/fixtures/expander_brutal_flat.rb
|
158
171
|
- test/fixtures/rules_empty.rb
|
159
172
|
- test/fixtures/rules_missing_path.rb
|
160
173
|
- test/fixtures/rules_no_check.rb
|
161
174
|
- test/fixtures/rules_type_and_min_children.rb
|
162
175
|
- test/fixtures/rules_type_check.rb
|
163
176
|
- test/unit/attr_set_spec.rb
|
177
|
+
- test/unit/attr_set_spec_wildcard.rb
|
164
178
|
- test/unit/check_child_count_spec.rb
|
165
179
|
- test/unit/check_looks_like_spec.rb
|
166
180
|
- test/unit/check_regex_spec.rb
|
167
181
|
- test/unit/check_required_spec.rb
|
168
182
|
- test/unit/check_type_spec.rb
|
183
|
+
- test/unit/expanders/brutal_regex_spec.rb
|
169
184
|
- test/unit/rule_parse_spec.rb
|
170
185
|
- test/unit/spec_helper.rb
|