ecomdev-chefspec 0.1.2 → 0.1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9855c65317cdbad908e4b3ce31121b2d92df1ccc
4
- data.tar.gz: 506884fda82363e731a0042082bf658dc99a5fc7
3
+ metadata.gz: ee3608b8e1aab45a9fa3e0aa5a56321e1347c6a6
4
+ data.tar.gz: a625c05596c7a54a438c6861a4bdb04957227fb0
5
5
  SHA512:
6
- metadata.gz: a091b003633864e953be4c4e8cafa4fb823c408e1ed1527bbf74783d19558bf24d1383b1d33359f2d711c8eb583241be76c3bb5e8c9fa9878c0a6cd07e9412df
7
- data.tar.gz: d00fa8ba662a776846225bde8657ee92183be41c3f4525f023c44bdf739d3d3a46b4a0a4d21175f18d2965ef4f4c02effe48024c07ab62025a81d1899b2b34fc
6
+ metadata.gz: 889c672f43c8afdfc5b61dc91b3235d415c5d038a27280c562ce772144ba8cbd6452ddc6464ed62ad2accf25db2cbda78e682e1743bb0f4d8ae7b17be0134eff
7
+ data.tar.gz: d4c0b510f3ab8fe4ab351658d8d55ea48d497fc9e6830225687542551f31ab5f6a1b97df8521a346133a340107e168aaa4b9e1ae2aa47f7d3ef567a5e2bf313e
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ .idea/*
1
2
  *.gem
2
3
  *.rbc
3
4
  .bundle
data/README.md CHANGED
@@ -29,6 +29,50 @@ Features:
29
29
  * Berkshelf or Librarian path if any of those was included before
30
30
  * `path/to/your/test/cookbooks`
31
31
  * `another/path/to/your/test/cookbooks`
32
+
33
+ * Allows to create platform based test cases by calling `platform(*filters)` method. Platform file is a json of such a structure:
34
+
35
+ ```javascript
36
+ {
37
+ "os": {
38
+ "ubuntu": ["10.04", "12.04", "13.10", "14.04"],
39
+ "debian": ["6.0.5", "7.2", "7.4"],
40
+ "freebsd": "9.2",
41
+ "centos": ["5.8","6.4", "6.5"],
42
+ "redhat": ["5.6", "6.3", "6.4"],
43
+ "fedora": ["18", "19", "20"]
44
+ },
45
+ "family": {
46
+ "debian": ["ubuntu", "debian"],
47
+ "rhel": ["redhat", "centos"],
48
+ "fedora": ["fedora"],
49
+ "freebsd": ["freebsd"]
50
+ }
51
+ }
52
+ ```
53
+
54
+ By default this file is read from such location spec/platform.json. You can override it by specifying `EcomDev::ChefSpec::Helpers::Platform.platform_path='path/to/dir'` and `EcomDev::ChefSpec::Helpers::Platform.platform_file='file.json'` or directly by calling `platform_load(file, path)` in your test case body
55
+
56
+ When calling `platform` method you can pass a ruby block, so it will iterate over specified platforms:
57
+
58
+ ```ruby
59
+ platform(:debian, :ubuntu) do |os, version|
60
+ context 'In scope of ' + os + ' ' + version do
61
+ it 'does crazy thing' do
62
+ # .. you test code
63
+ end
64
+ end
65
+ end
66
+ ```
67
+
68
+ it will produce the following output:
69
+
70
+ ```
71
+ In scope of ubuntu 14.04
72
+ does crazy things
73
+ In scope of debian 7.4
74
+ does crazy things
75
+ ```
32
76
 
33
77
 
34
78
  ## Build Status
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency 'chefspec', '~> 4.0'
22
+ spec.add_dependency 'json'
22
23
  spec.add_development_dependency "bundler", "~> 1.6"
23
24
  spec.add_development_dependency "rake"
24
25
  end
@@ -0,0 +1,20 @@
1
+ module RSpec::Core::MemoizedHelpers::ClassMethods
2
+ def platform_load(file = nil, path = nil)
3
+ @platform = EcomDev::ChefSpec::Helpers::Platform.new(file, path)
4
+ end
5
+
6
+ def platform(*args)
7
+ if @platform.nil?
8
+ platform_load
9
+ end
10
+
11
+ platforms = @platform.filter(*args)
12
+ unless block_given?
13
+ return platforms
14
+ end
15
+
16
+ platforms.each do |platform|
17
+ yield platform[:os].to_s, platform[:version].to_s
18
+ end
19
+ end
20
+ end
@@ -1,143 +1,7 @@
1
1
  module ChefSpec::API
2
2
  module EcomDevHelpersRunner
3
3
  def chef_run_proxy
4
- RunnerProxy
5
- end
6
-
7
- class RunnerProxy
8
- instance_methods.each { |m| undef_method m unless m =~ /(^instance_variable_get|^initialize|^__|^send$|^object_id$)/ }
9
-
10
- def initialize(*args, &before_initialize)
11
- @args = args
12
- @constructor_block = before_initialize
13
- @target = nil
14
- @blocks = {
15
- :before => {},
16
- :block => {},
17
- :after => {}
18
- }
19
- end
20
-
21
- def options(options = {}, override = false)
22
- if @args.length == 0
23
- @args << options
24
- return @args[0]
25
- end
26
- if override
27
- @args[0] = options
28
- else
29
- @args[0] = options.merge(@args[0])
30
- end
31
- @args[0]
32
- end
33
-
34
- def before(method, instance_eval = true, &block)
35
- define_proxy_block(method, :before, instance_eval, &block)
36
- end
37
-
38
- def after(method, instance_eval = true, &block)
39
- define_proxy_block(method, :after, instance_eval, &block)
40
- end
41
-
42
- def block(method, instance_eval = true, &block)
43
- define_proxy_block(method, :block, instance_eval, &block)
44
- end
45
-
46
- def proxy_blocks
47
- @blocks
48
- end
49
-
50
- def runner
51
- target
52
- end
53
-
54
- # Proxied chef runner
55
- protected
56
- def define_proxy_block(method, type, instance_eval = true, &block)
57
- if block_given?
58
- @blocks[type][method] ||= Array.new
59
- @blocks[type][method] << {block: block, instance_eval: instance_eval}
60
- end
61
- end
62
-
63
- def block_for?(method, type)
64
- @blocks.key?(type) && @blocks[type].key?(method) && @blocks[type][method].is_a?(Array)
65
- end
66
-
67
- def invoke_blocks(method, type, *args, &block)
68
- blocks_to_exec = []
69
- if block_given?
70
- blocks_to_exec << {block: block, instance_eval: false, caller_block: true}
71
- end
72
-
73
- if block_for?(method, type)
74
- blocks_to_exec.push(@blocks[type][method]).flatten!
75
- end
76
-
77
- blocks_to_exec.each do |info|
78
- if info[:instance_eval]
79
- target.instance_exec(*args, &info[:block])
80
- else
81
- calling_args = args.clone
82
- unless info.key?(:caller_block) && info[:caller_block]
83
- calling_args.unshift(target)
84
- end
85
- info[:block].call(*calling_args)
86
- end
87
- end
88
- end
89
-
90
- def method_missing(name, *args, &block)
91
- invoke_blocks(name, :before, *args)
92
- result = target.send(name, *args) do |*block_args|
93
- invoke_blocks(name, :block, *block_args, &block)
94
- end
95
- args.unshift(result)
96
- invoke_blocks(name, :after, *args)
97
- result
98
- end
99
-
100
- def target
101
- unless @target.nil?
102
- return @target
103
- end
104
- block_args = nil
105
- @target = ChefSpec::Runner.new(*@args) do |*args|
106
- block_args = args
107
- end
108
- invoke_blocks(:initialize, :block, *block_args, &@constructor_block)
109
- @target
110
- end
111
-
112
- class << self
113
- def instance(*args, &block)
114
- proxy = self.new(*args, &block)
115
- proxy_calls.each do |call|
116
- proxy.send(call[:method], *call[:args], &call[:block])
117
- end
118
- reset
119
- proxy
120
- end
121
-
122
- def reset
123
- proxy_calls([])
124
- self
125
- end
126
-
127
- def method_missing(method, *args, &block)
128
- proxy_calls.push({method: method, args: args, block: block})
129
- self
130
- end
131
-
132
- private
133
- def proxy_calls(calls=nil)
134
- @calls ||= []
135
- unless calls.nil?
136
- @calls = calls
137
- end
138
- @calls
139
- end
140
- end
4
+ EcomDev::ChefSpec::Helpers::RunnerProxy
141
5
  end
142
6
  end
143
7
  end
@@ -1,38 +1,28 @@
1
1
  module ChefSpec::API
2
2
  module EcomDevMatcherMultilineString
3
3
 
4
- module Matcher
5
- extend self
6
-
7
- def matcher(expected)
8
- RSpec::Matchers::BuiltIn::Match.new(expected)
9
- end
10
-
11
- def regexp(match, before ='', after = '')
12
- unless match.is_a?(Regexp)
13
- match = ::Regexp.escape(match).tr_s('\\ ', '\\s')
14
- else
15
- match = match.source
16
- end
17
-
18
- ::Regexp.new(before + match + after, Regexp::MULTILINE)
19
- end
20
- end
21
-
22
4
  def start_line_with(match)
23
- Matcher::matcher(Matcher::regexp(match, '^'))
5
+ EcomDev::ChefSpec::Helpers::StringMatcher.instance_eval do
6
+ matcher(regexp(match, '^'))
7
+ end
24
8
  end
25
9
 
26
10
  def end_line_with(match)
27
- Matcher::matcher(Matcher::regexp(match, '', '$'))
11
+ EcomDev::ChefSpec::Helpers::StringMatcher.instance_eval do
12
+ matcher(regexp(match, '', '$'))
13
+ end
28
14
  end
29
15
 
30
16
  def contain_line(match)
31
- Matcher::matcher(Matcher::regexp(match, '^.*', '.*$'))
17
+ EcomDev::ChefSpec::Helpers::StringMatcher.instance_eval do
18
+ matcher(regexp(match, '^.*', '.*$'))
19
+ end
32
20
  end
33
21
 
34
22
  def contain_full_line(match)
35
- Matcher::matcher(Matcher::regexp(match, '^\s*', '\s*$'))
23
+ EcomDev::ChefSpec::Helpers::StringMatcher.instance_eval do
24
+ matcher(regexp(match, '^\s*', '\s*$'))
25
+ end
36
26
  end
37
27
  end
38
28
  end
@@ -12,5 +12,4 @@ module ChefSpec::API::EcomDevStubsFileSystem
12
12
  def stub_file_read(file, content, *additional_args)
13
13
  EcomDev::ChefSpec::Stub::FileSystem.instance.file_read(file, content, *additional_args)
14
14
  end
15
-
16
15
  end
@@ -4,4 +4,6 @@ require 'chefspec/api'
4
4
  require_relative 'api/stubs/include_recipe'
5
5
  require_relative 'api/stubs/file_system'
6
6
  require_relative 'api/matchers/multiline_string'
7
- require_relative 'api/helpers/runner'
7
+ require_relative 'helpers'
8
+ require_relative 'api/helpers/platform'
9
+ require_relative 'api/helpers/runner'
@@ -0,0 +1,184 @@
1
+ require 'pathname'
2
+ require 'json'
3
+
4
+ module EcomDev::ChefSpec::Helpers
5
+ class Platform
6
+ def initialize(file = nil, path = nil)
7
+ @os = {}
8
+ @family = {}
9
+
10
+ path ||= self.class.platform_path
11
+ file ||= self.class.platform_file
12
+
13
+ json_path = File.join(path, file)
14
+
15
+ if File.readable?(json_path)
16
+ load_json(File.read(json_path))
17
+ end
18
+ end
19
+
20
+ def load_json(json_str)
21
+ json = JSON.load(json_str)
22
+ if json.key?('os') && json['os'].is_a?(Hash)
23
+ json['os'].each_pair do |os, version|
24
+ @os[os.to_sym] ||= Array.new
25
+ unless version.is_a?(Array)
26
+ version = [version]
27
+ end
28
+ version.flatten.map {|v| v.to_s }.each do |v|
29
+ @os[os.to_sym] << v unless @os[os.to_sym].include?(v)
30
+ end
31
+ end
32
+ end
33
+
34
+ if json.key?('family') && json['family'].is_a?(Hash)
35
+ json['family'].each_pair do |family, os|
36
+ @family[family.to_sym] ||= Array.new
37
+ unless os.is_a?(Array)
38
+ os = [os]
39
+ end
40
+ os.flatten.map { |v| v.to_sym }.select { |v| @os.key?(v) }.each do |v|
41
+ @family[family.to_sym] << v unless @family[family.to_sym].include?(v)
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ # Returns list of available os versions filtered by conditions
48
+ #
49
+ # Each condition is treated as OR operation
50
+ # If no condition is specified all items are listed
51
+ # If TrueClass is supplied as one of the arguments it filters only last versions
52
+ #
53
+ def filter(*conditions)
54
+ latest = !conditions.select {|item| item === true }.empty?
55
+ filters = translate_conditions(conditions)
56
+ items = list(latest)
57
+ unless filters.empty?
58
+ items = items.select do |item|
59
+ !filters.select {|filter| match_filter(filter, item) }.empty?
60
+ end
61
+
62
+ end
63
+ items
64
+ end
65
+
66
+ def translate_conditions(conditions)
67
+ conditions.flatten!
68
+ previous_filter = previous_condition = nil
69
+ filters = []
70
+
71
+ reset_options = Proc.new do
72
+ previous_filter = previous_condition = nil
73
+ end
74
+
75
+ conditions.each do |condition|
76
+ unless condition.is_a?(Hash)
77
+ if is_version(condition) && is_os(previous_condition) && previous_filter
78
+ previous_filter[:version] ||= Array.new
79
+ previous_filter[:version] << condition.to_s
80
+ elsif is_os(condition)
81
+ previous_filter = {os: condition.to_sym}
82
+ filters << previous_filter
83
+ else
84
+ reset_options.call
85
+ end
86
+ else
87
+ reset_options.call
88
+ if condition.key?(:family)
89
+ condition[:family] = [condition[:family]] unless condition[:family].is_a?(Array)
90
+ condition[:family].select {|family| @family.key?(family) }.each do |family|
91
+ @family[family].each { |os| filters << {os: os} }
92
+ end
93
+ elsif condition.key?(:os)
94
+ condition[:version] ||= []
95
+ condition[:version] = [condition[:version]] if condition[:version].is_a?(String)
96
+ filters << condition
97
+ end
98
+ end
99
+ end
100
+ filters
101
+ end
102
+
103
+ # Returns `true` if provided value is a version string
104
+ # @param string [String, Symbol] value to check
105
+ # @return [TrueClass, FalseClass]
106
+ def is_version(string)
107
+ return false if string === false || string === true || string.nil?
108
+ string.to_s.match(/^\d+[\d\.a-zA-Z\-_~]*/)
109
+ end
110
+
111
+ # Returns `true` if provided value is a registered OS
112
+ # @param string [String, Symbol] value to check
113
+ # @return [TrueClass, FalseClass]
114
+ def is_os(string)
115
+ return false if string === false || string === true || string.nil?
116
+ @os.key?(string.to_sym)
117
+ end
118
+
119
+ # Returns true if item matches filter conditions
120
+ # @param filter [Hash{Symbol => String, Symbol}]
121
+ # @param item [Hash{Symbol => String, Symbol}]
122
+ # @return [true, false]
123
+ def match_filter(filter, item)
124
+ filter.each_pair do |key, value|
125
+ unless item.key?(key)
126
+ return false
127
+ end
128
+ unless value.is_a?(Array)
129
+ return false if value != item[key]
130
+ else
131
+ return true if value.empty?
132
+ return false unless value.include?(item[key])
133
+ end
134
+ end
135
+ true
136
+ end
137
+
138
+ # Mark as private internal methods
139
+ private :is_os, :is_version, :translate_conditions, :match_filter
140
+
141
+ # Returns list of available os versions
142
+ # @param [TrueClass, FalseClass] latest specify if would like to receive only latest
143
+ # @return [Array<Hash{Symbol => String, Symbol}>] list of os versions in view of hash
144
+ def list(latest = false)
145
+ result = []
146
+ @os.map do |os, versions|
147
+ unless latest
148
+ versions.each { |version| result << {os: os, version: version}}
149
+ else
150
+ result << {os: os, version: versions.last} if versions.length > 0
151
+ end
152
+ end
153
+ result
154
+ end
155
+
156
+ class << self
157
+ def platform_path
158
+ @platform_path ||= RSpec.configuration.default_path
159
+ end
160
+
161
+ def platform_path=(value)
162
+ unless value.nil?
163
+ value = Pathname.new value
164
+
165
+ if value.relative? && value.to_path[0] != '~'
166
+ value = Pathname.new File.join(RSpec.configuration.default_path, value.to_path)
167
+ end
168
+
169
+ value = value.to_path
170
+ end
171
+
172
+ @platform_path = value
173
+ end
174
+
175
+ def platform_file
176
+ @platform_file ||= 'platform.json'
177
+ end
178
+
179
+ def platform_file=(value)
180
+ @platform_file = value
181
+ end
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,137 @@
1
+ module EcomDev::ChefSpec::Helpers
2
+ class RunnerProxy
3
+ instance_methods.each { |m| undef_method m unless m =~ /(^instance_variable_get|^initialize|^__|^send$|^object_id$)/ }
4
+
5
+ def initialize(*args, &before_initialize)
6
+ @args = args
7
+ @constructor_block = before_initialize
8
+ @target = nil
9
+ @blocks = {
10
+ :before => {},
11
+ :block => {},
12
+ :after => {}
13
+ }
14
+ end
15
+
16
+ def options(options = {}, override = false)
17
+ if @args.length == 0
18
+ @args << options
19
+ return @args[0]
20
+ end
21
+ if override
22
+ @args[0] = options
23
+ else
24
+ @args[0] = options.merge(@args[0])
25
+ end
26
+ @args[0]
27
+ end
28
+
29
+ def before(method, instance_eval = true, &block)
30
+ define_proxy_block(method, :before, instance_eval, &block)
31
+ end
32
+
33
+ def after(method, instance_eval = true, &block)
34
+ define_proxy_block(method, :after, instance_eval, &block)
35
+ end
36
+
37
+ def block(method, instance_eval = true, &block)
38
+ define_proxy_block(method, :block, instance_eval, &block)
39
+ end
40
+
41
+ def proxy_blocks
42
+ @blocks
43
+ end
44
+
45
+ def runner
46
+ target
47
+ end
48
+
49
+ # Proxied chef runner
50
+ protected
51
+ def define_proxy_block(method, type, instance_eval = true, &block)
52
+ if block_given?
53
+ @blocks[type][method] ||= Array.new
54
+ @blocks[type][method] << {block: block, instance_eval: instance_eval}
55
+ end
56
+ end
57
+
58
+ def block_for?(method, type)
59
+ @blocks.key?(type) && @blocks[type].key?(method) && @blocks[type][method].is_a?(Array)
60
+ end
61
+
62
+ def invoke_blocks(method, type, *args, &block)
63
+ blocks_to_exec = []
64
+ if block_given?
65
+ blocks_to_exec << {block: block, instance_eval: false, caller_block: true}
66
+ end
67
+
68
+ if block_for?(method, type)
69
+ blocks_to_exec.push(@blocks[type][method]).flatten!
70
+ end
71
+
72
+ blocks_to_exec.each do |info|
73
+ if info[:instance_eval]
74
+ target.instance_exec(*args, &info[:block])
75
+ else
76
+ calling_args = args.clone
77
+ unless info.key?(:caller_block) && info[:caller_block]
78
+ calling_args.unshift(target)
79
+ end
80
+ info[:block].call(*calling_args)
81
+ end
82
+ end
83
+ end
84
+
85
+ def method_missing(name, *args, &block)
86
+ invoke_blocks(name, :before, *args)
87
+ result = target.send(name, *args) do |*block_args|
88
+ invoke_blocks(name, :block, *block_args, &block)
89
+ end
90
+ args.unshift(result)
91
+ invoke_blocks(name, :after, *args)
92
+ result
93
+ end
94
+
95
+ def target
96
+ unless @target.nil?
97
+ return @target
98
+ end
99
+ block_args = nil
100
+ @target = ChefSpec::Runner.new(*@args) do |*args|
101
+ block_args = args
102
+ end
103
+ invoke_blocks(:initialize, :block, *block_args, &@constructor_block)
104
+ @target
105
+ end
106
+
107
+ class << self
108
+ def instance(*args, &block)
109
+ proxy = self.new(*args, &block)
110
+ proxy_calls.each do |call|
111
+ proxy.send(call[:method], *call[:args], &call[:block])
112
+ end
113
+ reset
114
+ proxy
115
+ end
116
+
117
+ def reset
118
+ proxy_calls([])
119
+ self
120
+ end
121
+
122
+ def method_missing(method, *args, &block)
123
+ proxy_calls.push({method: method, args: args, block: block})
124
+ self
125
+ end
126
+
127
+ private
128
+ def proxy_calls(calls=nil)
129
+ @calls ||= []
130
+ unless calls.nil?
131
+ @calls = calls
132
+ end
133
+ @calls
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,19 @@
1
+ module EcomDev::ChefSpec::Helpers
2
+ module StringMatcher
3
+ extend self
4
+
5
+ def matcher(expected)
6
+ RSpec::Matchers::BuiltIn::Match.new(expected)
7
+ end
8
+
9
+ def regexp(match, before ='', after = '')
10
+ unless match.is_a?(::Regexp)
11
+ match = ::Regexp.escape(match).tr_s('\\ ', '\\s')
12
+ else
13
+ match = match.source
14
+ end
15
+
16
+ ::Regexp.new(before + match + after, Regexp::MULTILINE)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ module EcomDev::ChefSpec::Helpers
2
+ def self.helper(helper)
3
+ File.join(File.dirname(__FILE__), 'helpers', helper)
4
+ end
5
+
6
+ autoload :RunnerProxy, helper('runner_proxy')
7
+ autoload :StringMatcher, helper('string_matcher')
8
+ autoload :Platform, helper('platform')
9
+ end
@@ -13,7 +13,9 @@ module EcomDev
13
13
 
14
14
  def self.load(filename)
15
15
  dsl = new
16
- dsl.instance_eval(File.read(filename), filename)
16
+ content = File.read(filename)
17
+ content.taint
18
+ dsl.instance_eval(content, filename)
17
19
  dsl
18
20
  end
19
21
  end
@@ -1,6 +1,6 @@
1
1
 
2
2
  module EcomDev
3
3
  module ChefSpec
4
- VERSION = '0.1.2'
4
+ VERSION = '0.1.3'
5
5
  end
6
6
  end
@@ -2,5 +2,6 @@ require 'chefspec' unless defined?(ChefSpec) # Require chef spec only if it is n
2
2
 
3
3
  require_relative 'chefspec/version'
4
4
  require_relative 'chefspec/configuration'
5
+ require_relative 'chefspec/helpers'
5
6
  require_relative 'chefspec/resource/matcher'
6
7
  require_relative 'chefspec/api'
@@ -0,0 +1,35 @@
1
+ describe 'extends to base example group' do
2
+ platform_load('platforms.json', File.dirname(__FILE__))
3
+
4
+ platform(true) do |name, version|
5
+ context 'In scope of ' + name + ' ' + version + ' ' do
6
+ it 'does crazy things' do
7
+ expect(true).to eq(true)
8
+ end
9
+ end
10
+ end
11
+
12
+ platform(:ubuntu, :debian) do |name, version|
13
+ context 'In filtered scope of ' + name + ' ' + version + ' ' do
14
+ it 'does another crazy things' do
15
+ expect(true).to eq(true)
16
+ end
17
+ end
18
+ end
19
+
20
+ platform(family: [:debian]) do |name, version|
21
+ context 'In family filtered scope of ' + name + ' ' + version + ' ' do
22
+ it 'does another crazy things' do
23
+ expect(true).to eq(true)
24
+ end
25
+ end
26
+ end
27
+
28
+ platform({family: [:debian]}, true) do |name, version|
29
+ context 'In family filtered scope of latest ' + name + '' do
30
+ it 'does another crazy things on version ' + version do
31
+ expect(true).to eq(true)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,16 @@
1
+ {
2
+ "os": {
3
+ "ubuntu": ["10.04", "12.04", "13.10", "14.04"],
4
+ "debian": ["6.0.5", "7.2", "7.4"],
5
+ "freebsd": ["9.2"],
6
+ "centos": ["5.8","6.4", "6.5"],
7
+ "redhat": ["5.6", "6.3", "6.4"],
8
+ "fedora": ["18", "19", "20"]
9
+ },
10
+ "family": {
11
+ "debian": ["ubuntu", "debian"],
12
+ "rhel": ["redhat", "centos"],
13
+ "fedora": ["fedora"],
14
+ "freebsd": ["freebsd"]
15
+ }
16
+ }
@@ -1,6 +1,6 @@
1
1
 
2
2
  describe ChefSpec::API::EcomDevHelpersRunner do
3
3
  it 'returns a chef runner proxy class' do
4
- expect(chef_run_proxy).to eq(described_class::RunnerProxy)
4
+ expect(chef_run_proxy).to eq(EcomDev::ChefSpec::Helpers::RunnerProxy)
5
5
  end
6
6
  end
@@ -0,0 +1,193 @@
1
+ describe EcomDev::ChefSpec::Helpers::Platform do
2
+ before (:each) do
3
+ described_class.platform_path = nil
4
+ described_class.platform_file = nil
5
+ end
6
+
7
+ let (:json_data) { '{"os": {"ubuntu": [14.01, 12.04], "debian": 6, "freebsd": 3.4}, "family": {"debian": ["ubuntu", "debian", "unknown"], "freebsd": ["freebsd"]}}' }
8
+ let (:os) { {ubuntu: %w(14.01 12.04), debian: %w(6), freebsd: %w(3.4)} }
9
+ let (:family) { {debian: [:ubuntu, :debian], freebsd: [:freebsd]}}
10
+
11
+ describe '#platform_path' do
12
+ it 'equals to rspec directory by default' do
13
+ expect(described_class.platform_path).to eq(RSpec.configuration.default_path)
14
+ end
15
+
16
+ it 'makes possible to read from default path' do
17
+ expect(File.directory?(described_class.platform_path)).to eq(true)
18
+ end
19
+ end
20
+
21
+ describe '#platform_path=' do
22
+ it 'sets platform path to relative path within specs directory' do
23
+ described_class.platform_path = 'relative'
24
+ expect(described_class.platform_path).to eq(File.join(RSpec.configuration.default_path, 'relative'))
25
+ end
26
+
27
+ it 'sets platform path to absolute path if absolute path value is specified' do
28
+ described_class.platform_path = '~/chefspec'
29
+ expect(described_class.platform_path).to eq('~/chefspec')
30
+ end
31
+ end
32
+
33
+ describe '#platform_file' do
34
+ it 'equals to platform.json by default' do
35
+ expect(described_class.platform_file).to eq('platform.json')
36
+ end
37
+ end
38
+
39
+ describe '#platform_file=' do
40
+ it 'equals to platform.json by default' do
41
+ described_class.platform_file = 'custom.json'
42
+ expect(described_class.platform_file).to eq('custom.json')
43
+ end
44
+ end
45
+
46
+ describe '#initialize' do
47
+ it 'loads platform list from JSON file' do
48
+ expect(described_class).to receive(:platform_file).and_return('custom.json')
49
+ expect(described_class).to receive(:platform_path).and_return('/custom/files')
50
+
51
+ expect(File).to receive(:readable?).with(File.join('/custom/files', 'custom.json')).and_return(true)
52
+ expect(File).to receive(:read).with(File.join('/custom/files', 'custom.json'))
53
+ .and_return(json_data)
54
+ expect_any_instance_of(described_class).to receive(:load_json).with(json_data)
55
+ described_class.new
56
+ end
57
+
58
+ it 'loads platform list from JSON file specified in arguments' do
59
+ expect(described_class).not_to receive(:platform_file)
60
+ expect(described_class).to receive(:platform_path).and_return('/custom/files')
61
+
62
+ expect(File).to receive(:readable?).with(File.join('/custom/files', 'custom.json')).and_return(true)
63
+ expect(File).to receive(:read).with(File.join('/custom/files', 'custom.json'))
64
+ .and_return(json_data)
65
+ expect_any_instance_of(described_class).to receive(:load_json).with(json_data)
66
+ described_class.new('custom.json')
67
+ end
68
+
69
+ it 'loads platform list from JSON file that is specified in arguments with path' do
70
+ expect(described_class).not_to receive(:platform_file)
71
+ expect(described_class).not_to receive(:platform_path)
72
+
73
+ expect(File).to receive(:readable?).with(File.join('/custom/files', 'custom.json')).and_return(true)
74
+ expect(File).to receive(:read).with(File.join('/custom/files', 'custom.json'))
75
+ .and_return(json_data)
76
+ expect_any_instance_of(described_class).to receive(:load_json).with(json_data)
77
+ described_class.new('custom.json', '/custom/files')
78
+ end
79
+
80
+ it 'does not load any json file, if file is not readable' do
81
+ expect(described_class).to receive(:platform_file).and_return('custom.json')
82
+ expect(described_class).to receive(:platform_path).and_return('/custom/files')
83
+
84
+ expect(File).to receive(:readable?).with(File.join('/custom/files', 'custom.json')).and_return(false)
85
+ expect_any_instance_of(described_class).not_to receive(:load_json)
86
+ described_class.new
87
+ end
88
+ end
89
+
90
+ describe '#load_json' do
91
+ it 'loads json structure into os and family properties' do
92
+ platform = described_class.new
93
+
94
+ expect(platform.instance_variable_get(:@os)).to be_instance_of(Hash).and be_empty
95
+ expect(platform.instance_variable_get(:@family)).to be_instance_of(Hash).and be_empty
96
+
97
+ platform.load_json(json_data)
98
+
99
+ expect(platform.instance_variable_get(:@os)).to eq(os)
100
+ expect(platform.instance_variable_get(:@family)).to eq(family)
101
+ end
102
+ end
103
+
104
+ describe '#filter' do
105
+ it 'it filters by os names in string' do
106
+ platform = described_class.new
107
+ platform.instance_variable_set(:@os, os)
108
+ platform.instance_variable_set(:@family, family)
109
+
110
+ expect(platform.filter('ubuntu', :debian)).to eq([{os: :ubuntu, version: '14.01'},
111
+ {os: :ubuntu, version: '12.04'},
112
+ {os: :debian, version: '6'}])
113
+
114
+
115
+ end
116
+
117
+ it 'it filters by os name and version' do
118
+ platform = described_class.new
119
+ platform.instance_variable_set(:@os, os)
120
+ platform.instance_variable_set(:@family, family)
121
+
122
+ expect(platform.filter('debian', '6')).to eq([os: :debian, version: '6'])
123
+ end
124
+
125
+ it 'it filters by os version hash' do
126
+ platform = described_class.new
127
+ platform.instance_variable_set(:@os, os)
128
+ platform.instance_variable_set(:@family, family)
129
+
130
+ expect(platform.filter(:os => :debian, :version => '6')).to eq([{os: :debian, version: '6'}])
131
+ end
132
+
133
+ it 'accepts multiple hashes' do
134
+ platform = described_class.new
135
+ platform.instance_variable_set(:@os, os)
136
+ platform.instance_variable_set(:@family, family)
137
+
138
+ expect(platform.filter(
139
+ {:os => :debian, :version => '6'},
140
+ {:os => :freebsd}
141
+ )).to eq([{os: :debian, version: '6'}, {os: :freebsd, version: '3.4'}])
142
+ end
143
+
144
+ it 'accepts multiple string symbol conditions' do
145
+ platform = described_class.new
146
+ platform.instance_variable_set(:@os, os)
147
+ platform.instance_variable_set(:@family, family)
148
+
149
+ expect(platform.filter(:debian, '6', 'freebsd')).to eq([{os: :debian, version: '6'}, {os: :freebsd, version: '3.4'}])
150
+ end
151
+
152
+
153
+ it 'it filters by os family' do
154
+ platform = described_class.new
155
+ platform.instance_variable_set(:@os, os)
156
+ platform.instance_variable_set(:@family, family)
157
+
158
+ expect(platform.filter(:family => :debian)).to eq([{os: :ubuntu, version: '14.01'},
159
+ {os: :ubuntu, version: '12.04'},
160
+ {os: :debian, version: '6'}])
161
+
162
+ expect(platform.filter(:family => [:debian, :freebsd])).to eq([{os: :ubuntu, version: '14.01'},
163
+ {os: :ubuntu, version: '12.04'},
164
+ {os: :debian, version: '6'},
165
+ {os: :freebsd, version: '3.4'}])
166
+ end
167
+ end
168
+
169
+ describe '#list' do
170
+ it 'it lists all os systems' do
171
+ platform = described_class.new
172
+ platform.instance_variable_set(:@os, os)
173
+ platform.instance_variable_set(:@family, family)
174
+
175
+ expect(platform.list).to eq([{os: :ubuntu, version: '14.01'},
176
+ {os: :ubuntu, version: '12.04'},
177
+ {os: :debian, version: '6'},
178
+ {os: :freebsd, version: '3.4'}])
179
+
180
+ end
181
+
182
+ it 'it lists only latest os versions' do
183
+ platform = described_class.new
184
+ platform.instance_variable_set(:@os, os)
185
+ platform.instance_variable_set(:@family, family)
186
+
187
+ # NOTE: it should return last item of array, not latest version by number
188
+ expect(platform.list(true)).to eq([{os: :ubuntu, version: '12.04'},
189
+ {os: :debian, version: '6'},
190
+ {os: :freebsd, version: '3.4'}])
191
+ end
192
+ end
193
+ end
@@ -1,5 +1,5 @@
1
1
 
2
- describe ChefSpec::API::EcomDevHelpersRunner::RunnerProxy do
2
+ describe EcomDev::ChefSpec::Helpers::RunnerProxy do
3
3
  it 'does not create any method unless method of runner is executed' do
4
4
  runner_proxy = described_class.new
5
5
  expect(runner_proxy.instance_variable_get('@target')).to be_nil
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ecomdev-chefspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivan Chepurnyi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-21 00:00:00.000000000 Z
11
+ date: 2014-07-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chefspec
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '4.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: json
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -71,11 +85,16 @@ files:
71
85
  - lib/ecomdev-chefspec.rb
72
86
  - lib/ecomdev/chefspec.rb
73
87
  - lib/ecomdev/chefspec/api.rb
88
+ - lib/ecomdev/chefspec/api/helpers/platform.rb
74
89
  - lib/ecomdev/chefspec/api/helpers/runner.rb
75
90
  - lib/ecomdev/chefspec/api/matchers/multiline_string.rb
76
91
  - lib/ecomdev/chefspec/api/stubs/file_system.rb
77
92
  - lib/ecomdev/chefspec/api/stubs/include_recipe.rb
78
93
  - lib/ecomdev/chefspec/configuration.rb
94
+ - lib/ecomdev/chefspec/helpers.rb
95
+ - lib/ecomdev/chefspec/helpers/platform.rb
96
+ - lib/ecomdev/chefspec/helpers/runner_proxy.rb
97
+ - lib/ecomdev/chefspec/helpers/string_matcher.rb
79
98
  - lib/ecomdev/chefspec/resource/matcher.rb
80
99
  - lib/ecomdev/chefspec/resource/matcher/dsl.rb
81
100
  - lib/ecomdev/chefspec/resource/matcher/helper.rb
@@ -83,12 +102,15 @@ files:
83
102
  - lib/ecomdev/chefspec/stub/include_recipe.rb
84
103
  - lib/ecomdev/chefspec/version.rb
85
104
  - spec/spec_helper.rb
86
- - spec/unit/api/helpers/runner/proxy_spec.rb
105
+ - spec/unit/api/helpers/platform_spec.rb
106
+ - spec/unit/api/helpers/platforms.json
87
107
  - spec/unit/api/helpers/runner_spec.rb
88
108
  - spec/unit/api/matchers/multiline_string_spec.rb
89
109
  - spec/unit/api/stubs/file_system_spec.rb
90
110
  - spec/unit/api/stubs/include_recipe_spec.rb
91
111
  - spec/unit/configuration_spec.rb
112
+ - spec/unit/helpers/platform_spec.rb
113
+ - spec/unit/helpers/runner_proxy_spec.rb
92
114
  - spec/unit/matcher/dsl_spec.rb
93
115
  - spec/unit/matcher/helper_spec.rb
94
116
  - spec/unit/matcher_spec.rb
@@ -120,12 +142,15 @@ specification_version: 4
120
142
  summary: A collection of helpers for chef spec, to make easier writing recipe specs
121
143
  test_files:
122
144
  - spec/spec_helper.rb
123
- - spec/unit/api/helpers/runner/proxy_spec.rb
145
+ - spec/unit/api/helpers/platform_spec.rb
146
+ - spec/unit/api/helpers/platforms.json
124
147
  - spec/unit/api/helpers/runner_spec.rb
125
148
  - spec/unit/api/matchers/multiline_string_spec.rb
126
149
  - spec/unit/api/stubs/file_system_spec.rb
127
150
  - spec/unit/api/stubs/include_recipe_spec.rb
128
151
  - spec/unit/configuration_spec.rb
152
+ - spec/unit/helpers/platform_spec.rb
153
+ - spec/unit/helpers/runner_proxy_spec.rb
129
154
  - spec/unit/matcher/dsl_spec.rb
130
155
  - spec/unit/matcher/helper_spec.rb
131
156
  - spec/unit/matcher_spec.rb