chefspec 4.7.0 → 5.0.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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +7 -21
  3. data/CHANGELOG.md +18 -0
  4. data/Gemfile +1 -0
  5. data/README.md +37 -20
  6. data/chefspec.gemspec +4 -4
  7. data/examples/apt_repository/recipes/add.rb +8 -0
  8. data/examples/apt_repository/recipes/remove.rb +4 -0
  9. data/examples/apt_repository/spec/add_spec.rb +14 -0
  10. data/examples/apt_repository/spec/remove_spec.rb +9 -0
  11. data/examples/apt_update/recipes/periodic.rb +5 -0
  12. data/examples/apt_update/recipes/update.rb +3 -0
  13. data/examples/apt_update/spec/periodic_spec.rb +14 -0
  14. data/examples/apt_update/spec/update_spec.rb +9 -0
  15. data/examples/attributes/spec/default_spec.rb +1 -1
  16. data/examples/notifications/recipes/before.rb +7 -0
  17. data/examples/notifications/spec/before_spec.rb +16 -0
  18. data/examples/server/spec/node_spec.rb +3 -3
  19. data/examples/server/spec/search_spec.rb +4 -4
  20. data/examples/stub_node/spec/default_spec.rb +2 -2
  21. data/examples/subscribes/recipes/before.rb +5 -0
  22. data/examples/subscribes/spec/before_spec.rb +16 -0
  23. data/examples/user/spec/create_spec.rb +1 -1
  24. data/examples/user/spec/lock_spec.rb +1 -1
  25. data/examples/user/spec/manage_spec.rb +1 -1
  26. data/examples/user/spec/modify_spec.rb +1 -1
  27. data/examples/user/spec/remove_spec.rb +1 -1
  28. data/examples/user/spec/unlock_spec.rb +1 -1
  29. data/features/chocolatey_package.feature +0 -10
  30. data/features/dsc_resource.feature +0 -9
  31. data/features/notifications.feature +8 -0
  32. data/features/reboot.feature +0 -7
  33. data/features/step_into.feature +0 -7
  34. data/features/subscribes.feature +8 -0
  35. data/features/windows_package.feature +0 -9
  36. data/features/windows_service.feature +0 -7
  37. data/gemfiles/chefspec.gemfile +6 -0
  38. data/lib/chefspec/api/apt_repository.rb +56 -0
  39. data/lib/chefspec/api/apt_update.rb +53 -0
  40. data/lib/chefspec/cacher.rb +3 -2
  41. data/lib/chefspec/coverage.rb +38 -5
  42. data/lib/chefspec/errors.rb +3 -0
  43. data/lib/chefspec/extensions/chef/data_query.rb +2 -2
  44. data/lib/chefspec/matchers/notifications_matcher.rb +23 -2
  45. data/lib/chefspec/matchers/subscribes_matcher.rb +9 -0
  46. data/lib/chefspec/version.rb +1 -1
  47. data/spec/spec_helper.rb +5 -0
  48. data/spec/unit/cacher_spec.rb +17 -1
  49. data/spec/unit/matchers/notifications_matcher_spec.rb +1 -0
  50. data/spec/unit/matchers/subscribes_matcher_spec.rb +1 -0
  51. data/spec/unit/solo_runner_spec.rb +1 -1
  52. data/templates/coverage/json.erb +8 -0
  53. data/templates/coverage/table.erb +14 -0
  54. data/templates/errors/erb_template_parse_error.erb +5 -0
  55. data/templates/errors/template_not_found.erb +9 -0
  56. metadata +26 -11
  57. data/spec/unit/extensions/lwrp_base_spec.rb +0 -96
@@ -2,8 +2,8 @@ require 'chefspec'
2
2
 
3
3
  describe 'stub_node::default' do
4
4
  let(:my_node) do
5
- stub_node('example.com', platform: 'ubuntu', version: '12.04') do |node|
6
- node.set['foo']['bar'] = 'zip'
5
+ stub_node('example.com', platform: 'ubuntu', version: '14.04') do |node|
6
+ node.normal['foo']['bar'] = 'zip'
7
7
  end
8
8
  end
9
9
 
@@ -0,0 +1,5 @@
1
+ template '/tmp/notifying_resource'
2
+
3
+ service 'receiving_resource' do
4
+ subscribes :create, 'template[/tmp/notifying_resource]', :before
5
+ end
@@ -0,0 +1,16 @@
1
+ require 'chefspec'
2
+
3
+ describe 'subscribes::before' do
4
+ let(:chef_run) { ChefSpec::SoloRunner.converge(described_recipe) }
5
+ let(:service) { chef_run.service('receiving_resource') }
6
+
7
+ it 'subscribes to the template creation' do
8
+ expect(service).to subscribe_to('template[/tmp/notifying_resource]').before
9
+ expect(service).to_not subscribe_to('template[/tmp/not_notifying_resource]').before
10
+ end
11
+
12
+ it 'subscribes to the specific action on the resource before' do
13
+ expect(service).to subscribe_to('template[/tmp/notifying_resource]').on(:create).before
14
+ expect(service).to_not subscribe_to('template[/tmp/notifying_resource]').on(:delete).immediately
15
+ end
16
+ end
@@ -1,7 +1,7 @@
1
1
  require 'chefspec'
2
2
 
3
3
  describe 'user::create' do
4
- let(:chef_run) { ChefSpec::SoloRunner.converge(described_recipe) }
4
+ let(:chef_run) { ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '14.04').converge(described_recipe) }
5
5
 
6
6
  it 'creates a user with the default action' do
7
7
  expect(chef_run).to create_user('default_action')
@@ -1,7 +1,7 @@
1
1
  require 'chefspec'
2
2
 
3
3
  describe 'user::lock' do
4
- let(:chef_run) { ChefSpec::SoloRunner.converge(described_recipe) }
4
+ let(:chef_run) { ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '14.04').converge(described_recipe) }
5
5
 
6
6
  it 'locks a user with an explicit action' do
7
7
  expect(chef_run).to lock_user('explicit_action')
@@ -1,7 +1,7 @@
1
1
  require 'chefspec'
2
2
 
3
3
  describe 'user::manage' do
4
- let(:chef_run) { ChefSpec::SoloRunner.converge(described_recipe) }
4
+ let(:chef_run) { ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '14.04').converge(described_recipe) }
5
5
 
6
6
  it 'manages a user with an explicit action' do
7
7
  expect(chef_run).to manage_user('explicit_action')
@@ -1,7 +1,7 @@
1
1
  require 'chefspec'
2
2
 
3
3
  describe 'user::modify' do
4
- let(:chef_run) { ChefSpec::SoloRunner.converge(described_recipe) }
4
+ let(:chef_run) { ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '14.04').converge(described_recipe) }
5
5
 
6
6
  it 'modifys a user with an explicit action' do
7
7
  expect(chef_run).to modify_user('explicit_action')
@@ -1,7 +1,7 @@
1
1
  require 'chefspec'
2
2
 
3
3
  describe 'user::remove' do
4
- let(:chef_run) { ChefSpec::SoloRunner.converge(described_recipe) }
4
+ let(:chef_run) { ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '14.04').converge(described_recipe) }
5
5
 
6
6
  it 'removes a user with an explicit action' do
7
7
  expect(chef_run).to remove_user('explicit_action')
@@ -1,7 +1,7 @@
1
1
  require 'chefspec'
2
2
 
3
3
  describe 'user::unlock' do
4
- let(:chef_run) { ChefSpec::SoloRunner.converge(described_recipe) }
4
+ let(:chef_run) { ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '14.04').converge(described_recipe) }
5
5
 
6
6
  it 'unlocks a user with an explicit action' do
7
7
  expect(chef_run).to unlock_user('explicit_action')
@@ -1,17 +1,7 @@
1
- @not_chef_11_14_2
2
- @not_chef_11_14_6
3
- @not_chef_11_16_0
4
- @not_chef_11_16_2
5
- @not_chef_11_16_4
6
- @not_chef_11_18_0
7
- @not_chef_11_18_6
8
1
  @not_chef_12_0_3
9
- @not_chef_12_1_0
10
- @not_chef_12_1_1
11
2
  @not_chef_12_1_2
12
3
  @not_chef_12_2_1
13
4
  @not_chef_12_3_0
14
- @not_chef_12_4_0
15
5
  @not_chef_12_4_3
16
6
  @not_chef_12_5_1
17
7
  @not_chef_12_6_0
@@ -1,13 +1,4 @@
1
- @not_chef_11_14_2
2
- @not_chef_11_14_6
3
- @not_chef_11_16_0
4
- @not_chef_11_16_2
5
- @not_chef_11_16_4
6
- @not_chef_11_18_0
7
- @not_chef_11_18_6
8
1
  @not_chef_12_0_3
9
- @not_chef_12_1_0
10
- @not_chef_12_1_1
11
2
  @not_chef_12_1_2
12
3
  Feature: The dsc_resource matcher
13
4
  Background:
@@ -1,3 +1,10 @@
1
+ @not_chef_12_0_3
2
+ @not_chef_12_1_2
3
+ @not_chef_12_2_1
4
+ @not_chef_12_3_0
5
+ @not_chef_12_4_3
6
+ @not_chef_12_5_1
7
+
1
8
  Feature: The notifications matcher
2
9
  Background:
3
10
  * I am using the "notifications" cookbook
@@ -7,6 +14,7 @@ Feature: The notifications matcher
7
14
  * the output should contain "0 failures"
8
15
  Examples:
9
16
  | Matcher |
17
+ | before |
10
18
  | chained |
11
19
  | default |
12
20
  | delayed |
@@ -1,10 +1,3 @@
1
- @not_chef_11_14_2
2
- @not_chef_11_14_6
3
- @not_chef_11_16_0
4
- @not_chef_11_16_2
5
- @not_chef_11_16_4
6
- @not_chef_11_18_0
7
- @not_chef_11_18_6
8
1
  Feature: The reboot matcher
9
2
  Background:
10
3
  * I am using the "reboot" cookbook
@@ -1,10 +1,3 @@
1
- @not_chef_11_14_2
2
- @not_chef_11_14_6
3
- @not_chef_11_16_0
4
- @not_chef_11_16_2
5
- @not_chef_11_16_4
6
- @not_chef_11_18_0
7
- @not_chef_11_18_6
8
1
  Feature: The step_into matcher
9
2
  Background:
10
3
  * I am using the "step_into" cookbook
@@ -1,3 +1,10 @@
1
+ @not_chef_12_0_3
2
+ @not_chef_12_1_2
3
+ @not_chef_12_2_1
4
+ @not_chef_12_3_0
5
+ @not_chef_12_4_3
6
+ @not_chef_12_5_1
7
+
1
8
  Feature: The subscribes matcher
2
9
  Background:
3
10
  * I am using the "subscribes" cookbook
@@ -7,6 +14,7 @@ Feature: The subscribes matcher
7
14
  * the output should contain "0 failures"
8
15
  Examples:
9
16
  | Matcher |
17
+ | before |
10
18
  | chained |
11
19
  | default |
12
20
  | delayed |
@@ -1,13 +1,4 @@
1
- @not_chef_11_14_2
2
- @not_chef_11_14_6
3
- @not_chef_11_16_0
4
- @not_chef_11_16_2
5
- @not_chef_11_16_4
6
- @not_chef_11_18_0
7
- @not_chef_11_18_6
8
1
  @not_chef_12_0_3
9
- @not_chef_12_1_0
10
- @not_chef_12_1_1
11
2
  @not_chef_12_1_2
12
3
  @not_chef_12_2_1
13
4
  @not_chef_12_3_0
@@ -1,10 +1,3 @@
1
- @not_chef_11_14_2
2
- @not_chef_11_14_6
3
- @not_chef_11_16_0
4
- @not_chef_11_16_2
5
- @not_chef_11_16_4
6
- @not_chef_11_18_0
7
- @not_chef_11_18_6
8
1
  Feature: The windows_service matcher
9
2
  Background:
10
3
  * I am using the "windows_service" cookbook
@@ -1,5 +1,11 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ # travis runs on older chef releases failed while including
4
+ # rack 2.X on Ruby 2.1. When we remove Ruby 2.1 support this can go
5
+ if ENV['CHEF_VERSION'].to_f < 12.6
6
+ gem 'rack', '~> 1.0'
7
+ end
8
+
3
9
  if ENV['CHEF_VERSION'] == 'master'
4
10
  gem 'chef', github: 'chef/chef'
5
11
  else
@@ -0,0 +1,56 @@
1
+ module ChefSpec::API
2
+ # @since 3.0.0
3
+ module AptRepositoryMatchers
4
+ ChefSpec.define_matcher :apt_repository
5
+
6
+ #
7
+ # Assert that an +apt_repository+ resource exists in the Chef run with the
8
+ # action +:add+. Given a Chef Recipe that adds "rsyslog" as an
9
+ # +apt_repository+:
10
+ #
11
+ # apt_repository 'rsyslog' do
12
+ # uri 'ppa:adiscon/v8-stable'
13
+ # action :add
14
+ # end
15
+ #
16
+ # The Examples section demonstrates the different ways to test an
17
+ # +apt_repository+ resource with ChefSpec.
18
+ #
19
+ # @example Assert that an +apt_repository+ was added
20
+ # expect(chef_run).to add_apt_repository('rsyslog')
21
+ # @param [String, Regex] resource_name
22
+ # the name of the resource to match
23
+ #
24
+ # @return [ChefSpec::Matchers::ResourceMatcher]
25
+
26
+ def add_apt_repository(resource_name)
27
+ ChefSpec::Matchers::ResourceMatcher.new(:apt_repository, :add,
28
+ resource_name)
29
+ end
30
+
31
+ #
32
+ # Assert that an +apt_repository+ resource exists in the Chef run with the
33
+ # action +:remove+. Given a Chef Recipe that removes "rsyslog" as an
34
+ # +apt_repository+:
35
+ #
36
+ # apt_repository 'rsyslog' do
37
+ # uri 'ppa:adiscon/v8-stable'
38
+ # action :remove
39
+ # end
40
+ #
41
+ # The Examples section demonstrates the different ways to test an
42
+ # +apt_repository+ resource with ChefSpec.
43
+ #
44
+ # @example Assert that an +apt_repository+ was removed
45
+ # expect(chef_run).to remove_apt_repository('rsyslog')
46
+ # @param [String, Regex] resource_name
47
+ # the name of the resource to match
48
+ #
49
+ # @return [ChefSpec::Matchers::ResourceMatcher]
50
+
51
+ def remove_apt_repository(resource_name)
52
+ ChefSpec::Matchers::ResourceMatcher.new(:apt_repository, :remove,
53
+ resource_name)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,53 @@
1
+ module ChefSpec::API
2
+ # @since 3.0.0
3
+ module AptUpdateMatchers
4
+ ChefSpec.define_matcher :apt_update
5
+
6
+ #
7
+ # Assert that an +apt_update+ resource exists in the Chef run with the
8
+ # action +:update+. Given a Chef Recipe that adds "rsyslog" as a repository
9
+ # to update.
10
+ # apt_repository 'rsyslog' do
11
+ # action :update
12
+ # end
13
+ #
14
+ # The Examples section demonstrates the different ways to test an
15
+ # +apt_update+ resource with ChefSpec.
16
+ #
17
+ # @example Assert that an +apt_update+ was run
18
+ # expect(chef_run).to update_apt_update('rsyslog')
19
+ # @param [String, Regex] resource_name
20
+ # the name of the resource to match
21
+ #
22
+ # @return [ChefSpec::Matchers::ResourceMatcher]
23
+
24
+ def update_apt_update(resource_name)
25
+ ChefSpec::Matchers::ResourceMatcher.new(:apt_update, :update,
26
+ resource_name)
27
+ end
28
+
29
+ #
30
+ # Assert that an +apt_update+ resource exists in the Chef run
31
+ # with the action +:periodic+. Given a Chef Recipe that updates "rsyslog"
32
+ # as an +apt_update+: periodically
33
+ #
34
+ # apt_update 'rsyslog' do
35
+ # action :periodic
36
+ # end
37
+ #
38
+ # The Examples section demonstrates the different ways to test an
39
+ # +apt_update+ resource with ChefSpec.
40
+ #
41
+ # @example Assert that an +apt_update+ was updated periodically
42
+ # expect(chef_run).to periodic_apt_update('rsyslog')
43
+ # @param [String, Regex] resource_name
44
+ # the name of the resource to match
45
+ #
46
+ # @return [ChefSpec::Matchers::ResourceMatcher]
47
+
48
+ def periodic_apt_update(resource_name)
49
+ ChefSpec::Matchers::ResourceMatcher.new(:apt_update, :periodic,
50
+ resource_name)
51
+ end
52
+ end
53
+ end
@@ -35,8 +35,9 @@ module ChefSpec
35
35
 
36
36
  def cached(name, &block)
37
37
  location = ancestors.first.metadata[:location]
38
- unless ancestors.first.metadata[:description].nil? || location.nil?
39
- location += ancestors.first.metadata[:description]
38
+ unless location.nil?
39
+ location += ancestors.first.metadata[:description] unless ancestors.first.metadata[:description].nil?
40
+ location += ancestors.first.metadata[:scoped_id] unless ancestors.first.metadata[:scoped_id].nil?
40
41
  end
41
42
  location ||= ancestors.first.metadata[:parent_example_group][:location]
42
43
 
@@ -28,6 +28,7 @@ module ChefSpec
28
28
  def initialize
29
29
  @collection = {}
30
30
  @filters = {}
31
+ @template = ChefSpec.root.join('templates', 'coverage', 'human.erb')
31
32
  end
32
33
 
33
34
  #
@@ -67,7 +68,26 @@ module ChefSpec
67
68
 
68
69
  true
69
70
  end
70
-
71
+ #
72
+ # Change the template for reporting of converage analysis.
73
+ #
74
+ # @param [string] path
75
+ # The template file to use for the output of the report
76
+ #
77
+ # @return [true]
78
+ #
79
+ def set_template(file = 'human.erb')
80
+ [
81
+ ChefSpec.root.join('templates', 'coverage', file),
82
+ File.expand_path(file, Dir.pwd)
83
+ ].each do |temp|
84
+ if File.exist?(temp)
85
+ @template = temp
86
+ return
87
+ end
88
+ end
89
+ raise Error::TemplateNotFound.new(path: file)
90
+ end
71
91
  #
72
92
  # Add a resource to the resource collection. Only new resources are added
73
93
  # and only resources that match the given filter are covered (which is *
@@ -130,10 +150,14 @@ module ChefSpec
130
150
  report[:untouched_resources] = @collection.collect do |_, resource|
131
151
  resource unless resource.touched?
132
152
  end.compact
133
-
134
- template = ChefSpec.root.join('templates', 'coverage', 'human.erb')
135
- erb = Erubis::Eruby.new(File.read(template))
136
- puts erb.evaluate(report)
153
+ report[:all_resources] = @collection.values
154
+
155
+ begin
156
+ erb = Erubis::Eruby.new(File.read(@template))
157
+ puts erb.evaluate(report)
158
+ rescue NameError => e
159
+ raise Error::ErbTemplateParseError.new(original_error: e.message)
160
+ end
137
161
 
138
162
  # Ensure we exit correctly (#351)
139
163
  Kernel.exit(exit_status) if exit_status && exit_status > 0
@@ -160,6 +184,15 @@ module ChefSpec
160
184
  @resource.to_s
161
185
  end
162
186
 
187
+ def to_json
188
+ {
189
+ "source_file" => source_file,
190
+ "source_line" => source_line,
191
+ "touched" => touched?,
192
+ "resource" => to_s
193
+ }.to_json
194
+ end
195
+
163
196
  def source_file
164
197
  @source_file ||= if @resource.source_line
165
198
  shortname(@resource.source_line.split(':').first)
@@ -40,5 +40,8 @@ module ChefSpec
40
40
  class MayNeedToSpecifyPlatform < ChefSpecError; end
41
41
 
42
42
  class InvalidBerkshelfOptions < ChefSpecError; end
43
+
44
+ class TemplateNotFound < ChefSpecError; end
45
+ class ErbTemplateParseError < ChefSpecError; end
43
46
  end
44
47
  end
@@ -33,8 +33,8 @@ module Chef::DSL::DataQuery
33
33
 
34
34
  # @see Chef::DSL::DataQuery#data_bag_item
35
35
  alias_method :old_data_bag_item, :data_bag_item
36
- def data_bag_item(bag, id)
37
- return old_data_bag_item(bag, id) unless Chef::Config[:solo]
36
+ def data_bag_item(bag, id, secret = nil)
37
+ return old_data_bag_item(bag, id, secret) unless Chef::Config[:solo]
38
38
 
39
39
  stub = ChefSpec::Stubs::DataBagItemRegistry.stub_for(bag, id)
40
40