chefspec 4.7.0 → 5.0.0

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