ecomdev-chefspec 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
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