chefspec 7.3.3 → 7.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +23 -0
  3. data/Rakefile +77 -0
  4. data/chefspec.gemspec +29 -0
  5. data/lib/chefspec/version.rb +1 -1
  6. data/spec/spec_helper.rb +13 -0
  7. data/spec/support/hash.rb +35 -0
  8. data/spec/unit/cacher_spec.rb +70 -0
  9. data/spec/unit/coverage/filters_spec.rb +60 -0
  10. data/spec/unit/deprecations_spec.rb +53 -0
  11. data/spec/unit/errors_spec.rb +57 -0
  12. data/spec/unit/expect_exception_spec.rb +32 -0
  13. data/spec/unit/macros_spec.rb +119 -0
  14. data/spec/unit/matchers/do_nothing_matcher.rb +5 -0
  15. data/spec/unit/matchers/include_recipe_matcher_spec.rb +38 -0
  16. data/spec/unit/matchers/link_to_matcher_spec.rb +55 -0
  17. data/spec/unit/matchers/notifications_matcher_spec.rb +40 -0
  18. data/spec/unit/matchers/render_file_matcher_spec.rb +68 -0
  19. data/spec/unit/matchers/resource_matcher_spec.rb +5 -0
  20. data/spec/unit/matchers/state_attrs_matcher_spec.rb +68 -0
  21. data/spec/unit/matchers/subscribes_matcher_spec.rb +65 -0
  22. data/spec/unit/renderer_spec.rb +69 -0
  23. data/spec/unit/server_runner_spec.rb +28 -0
  24. data/spec/unit/solo_runner_spec.rb +171 -0
  25. data/spec/unit/stubs/command_registry_spec.rb +27 -0
  26. data/spec/unit/stubs/command_stub_spec.rb +61 -0
  27. data/spec/unit/stubs/data_bag_item_registry_spec.rb +39 -0
  28. data/spec/unit/stubs/data_bag_item_stub_spec.rb +36 -0
  29. data/spec/unit/stubs/data_bag_registry_spec.rb +39 -0
  30. data/spec/unit/stubs/data_bag_stub_spec.rb +35 -0
  31. data/spec/unit/stubs/registry_spec.rb +29 -0
  32. data/spec/unit/stubs/search_registry_spec.rb +39 -0
  33. data/spec/unit/stubs/search_stub_spec.rb +36 -0
  34. data/spec/unit/stubs/stub_spec.rb +64 -0
  35. metadata +34 -2
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe ChefSpec::ExpectException do
4
+ context 'when there have been no `raise_error` matchers' do
5
+ subject { described_class.new(Exception) }
6
+
7
+ it 'does not match' do
8
+ allow(RSpec::Matchers::BuiltIn::RaiseError).to receive(:last_run).and_return(nil)
9
+ expect(subject.expected?).to be_falsy
10
+ end
11
+ end
12
+
13
+ context 'when the last error does not match the expected type' do
14
+ subject { described_class.new(RuntimeError) }
15
+
16
+ it 'does not match' do
17
+ last_error = double('last error', last_error_for_chefspec: ArgumentError)
18
+ allow(RSpec::Matchers::BuiltIn::RaiseError).to receive(:last_run).and_return(last_error)
19
+ expect(subject.expected?).to be_falsy
20
+ end
21
+ end
22
+
23
+ context 'when the last error matches the expected type' do
24
+ subject { described_class.new(RuntimeError) }
25
+
26
+ it 'does not match' do
27
+ last_error = double('last error', last_error_for_chefspec: RuntimeError)
28
+ allow(RSpec::Matchers::BuiltIn::RaiseError).to receive(:last_run).and_return(last_error)
29
+ expect(subject.expected?).to be_truthy
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,119 @@
1
+ require 'spec_helper'
2
+
3
+ describe ChefSpec::API::Stubs do
4
+ describe '#stub_command' do
5
+ let(:command_stub) { double('command') }
6
+
7
+ it 'adds the command to the command registry' do
8
+ allow(ChefSpec::Stubs::CommandStub).to receive(:new).and_return(command_stub)
9
+ stub_command('echo "hello"')
10
+
11
+ expect(ChefSpec::Stubs::CommandRegistry.stubs).to include(command_stub)
12
+ end
13
+ end
14
+
15
+ describe '#stub_search' do
16
+ let(:search_stub) { double('search') }
17
+
18
+ it 'adds the query to the search registry' do
19
+ allow(ChefSpec::Stubs::SearchStub).to receive(:new).and_return(search_stub)
20
+ stub_search(:node, '*:*')
21
+
22
+ expect(ChefSpec::Stubs::SearchRegistry.stubs).to include(search_stub)
23
+ end
24
+ end
25
+
26
+ describe '#stub_data_bag' do
27
+ let(:data_bag_stub) { double('data_bag') }
28
+
29
+ it 'adds the query to the data_bag registry' do
30
+ allow(ChefSpec::Stubs::DataBagStub).to receive(:new).and_return(data_bag_stub)
31
+ stub_data_bag(:users)
32
+
33
+ expect(ChefSpec::Stubs::DataBagRegistry.stubs).to include(data_bag_stub)
34
+ end
35
+ end
36
+
37
+ describe '#stub_data_bag_item' do
38
+ let(:data_bag_item_stub) { double('data_bag_item') }
39
+
40
+ it 'adds the query to the data_bag_item registry' do
41
+ allow(ChefSpec::Stubs::DataBagItemStub).to receive(:new).and_return(data_bag_item_stub)
42
+ stub_data_bag_item(:users, 'id')
43
+
44
+ expect(ChefSpec::Stubs::DataBagItemRegistry.stubs).to include(data_bag_item_stub)
45
+ end
46
+ end
47
+
48
+ describe '#stub_node' do
49
+ it 'returns a Chef::Node' do
50
+ expect(stub_node).to be_a(Chef::Node)
51
+ end
52
+
53
+ it 'defaults the node name to `node.example`' do
54
+ node = stub_node
55
+ expect(node.name).to eq('node.example')
56
+ end
57
+
58
+ it 'sets the node name when given' do
59
+ node = stub_node('example.com')
60
+ expect(node.name).to eq('example.com')
61
+ end
62
+
63
+ it 'sets the automatic attributes' do
64
+ node = stub_node
65
+ expect(node.automatic).to eq(Fauxhai.mock.data)
66
+ end
67
+
68
+ it 'sets the automatic attributes with ohai overrides' do
69
+ node = stub_node('node.example', ohai: { ipaddress: '1.2.3.4' })
70
+ expect(node['ipaddress']).to eq('1.2.3.4')
71
+ end
72
+
73
+ it 'sets the automatic attributes for a specific platform and version' do
74
+ node = stub_node('node.example', platform: 'ubuntu', version: '18.04')
75
+ expect(node.automatic).to eq(Fauxhai.mock(platform: 'ubuntu', version: '18.04').data)
76
+ end
77
+
78
+ it 'sets the automatic attributes from a JSON data path' do
79
+ allow(File).to receive(:exist?).with('/path/to/json').and_return(true)
80
+ allow(File).to receive(:read).with('/path/to/json').and_return('{ "ipaddress": "1.2.3.4" }')
81
+ node = stub_node('node.example', path: '/path/to/json')
82
+ expect(node['ipaddress']).to eq('1.2.3.4')
83
+ end
84
+
85
+ it 'yields a block' do
86
+ expect { |block| stub_node(&block) }.to yield_with_args(Chef::Node)
87
+ end
88
+ end
89
+ end
90
+
91
+ describe 'nginx::source' do
92
+ describe '#described_cookbook' do
93
+ describe 'nginx::source' do
94
+ it 'returns the name of the cookbook' do
95
+ expect(described_cookbook).to eq('nginx')
96
+ end
97
+
98
+ context 'in a nested context' do
99
+ it 'still returns the name of the cookbook' do
100
+ expect(described_cookbook).to eq('nginx')
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ describe '#described_recipe' do
107
+ describe 'nginx::source' do
108
+ it 'returns the cookbook::recipe' do
109
+ expect(described_recipe).to eq('nginx::source')
110
+ end
111
+
112
+ context 'in a nested context' do
113
+ it 'still retrns the cookbook::recipe' do
114
+ expect(described_recipe).to eq('nginx::source')
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe ChefSpec::Matchers::DoNothingMatcher do
4
+ pending
5
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe ChefSpec::Matchers::IncludeRecipeMatcher do
4
+ let(:chef_run) { double('chef run', run_context: { loaded_recipes: %w(one two three) }) }
5
+ subject { described_class.new('one::default') }
6
+
7
+ describe '#failure_message' do
8
+ it 'has the right value' do
9
+ subject.matches?(chef_run)
10
+ expect(subject.failure_message)
11
+ .to eq(%q(expected ["one::default", "two::default", "three::default"] to include "one::default"))
12
+ end
13
+ end
14
+
15
+ describe '#failure_message_when_negated' do
16
+ it 'has the right value' do
17
+ subject.matches?(chef_run)
18
+ expect(subject.failure_message_when_negated)
19
+ .to eq(%q(expected "one::default" to not be included))
20
+ end
21
+ end
22
+
23
+ describe '#description' do
24
+ it 'has the right value' do
25
+ subject.matches?(chef_run)
26
+ expect(subject.description).to eq(%q(include recipe "one::default"))
27
+ end
28
+ end
29
+
30
+ it 'matches when the recipe is included' do
31
+ expect(subject.matches?(chef_run)).to be_truthy
32
+ end
33
+
34
+ it 'does not match when the recipe is not included' do
35
+ failure = described_class.new('nope')
36
+ expect(failure.matches?(chef_run)).to be_falsy
37
+ end
38
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe ChefSpec::Matchers::LinkToMatcher do
4
+ let(:from) { '/var/www' }
5
+ let(:to) { '/var/html' }
6
+ let(:link) do
7
+ Chef::Resource::Link.new(from).tap do |link|
8
+ link.to(to)
9
+ link.perform_action(:create)
10
+ end
11
+ end
12
+ subject { described_class.new(to) }
13
+
14
+ describe '#failure_message' do
15
+ it 'has the right value' do
16
+ subject.matches?(link)
17
+ expect(subject.failure_message)
18
+ .to eq(%Q(expected "link[#{from}]" to link to "#{to}" but was "#{to}"))
19
+ end
20
+ end
21
+
22
+ describe '#failure_message_when_negated' do
23
+ it 'has the right value' do
24
+ subject.matches?(link)
25
+ expect(subject.failure_message_when_negated)
26
+ .to eq(%Q(expected "link[#{from}]" to not link to "#{to}"))
27
+ end
28
+ end
29
+
30
+ describe '#description' do
31
+ it 'has the right value' do
32
+ subject.matches?(link)
33
+ expect(subject.description).to eq(%Q(link to "#{to}"))
34
+ end
35
+ end
36
+
37
+ context 'when the link is correct' do
38
+ it 'matches' do
39
+ expect(subject.matches?(link)).to be_truthy
40
+ end
41
+
42
+ it 'adds the link to the coverage report' do
43
+ expect(ChefSpec::Coverage).to receive(:cover!).with(link)
44
+ subject.matches?(link)
45
+ end
46
+ end
47
+
48
+ context 'when the link is not correct' do
49
+ subject { described_class.new('/nope/bad/path/bro') }
50
+
51
+ it 'does not match' do
52
+ expect(subject.matches?(link)).to be_falsy
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe ChefSpec::Matchers::NotificationsMatcher do
4
+ subject { described_class.new('execute[install]') }
5
+ let(:package) do
6
+ double('package',
7
+ name: 'package',
8
+ to_s: 'package[foo]',
9
+ is_a?: true,
10
+ performed_action?: true,
11
+ immediate_notifications: [],
12
+ delayed_notifications: [],
13
+ before_notifications: []
14
+ )
15
+ end
16
+
17
+ describe '#failure_message' do
18
+ it 'has the right value' do
19
+ subject.matches?(package)
20
+ expect(subject.failure_message)
21
+ .to include %|expected "package[foo]" to notify "execute[install]", but did not.|
22
+ end
23
+ end
24
+
25
+ describe '#failure_message_when_negated' do
26
+ it 'has the right value' do
27
+ subject.matches?(package)
28
+ expect(subject.failure_message_when_negated)
29
+ .to eq %|expected "package[foo]" to not notify "execute[install]", but it did.|
30
+ end
31
+ end
32
+
33
+ describe '#description' do
34
+ it 'has the right value' do
35
+ subject.matches?(package)
36
+ expect(subject.description)
37
+ .to eq %|notify "execute[install]"|
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+
3
+ describe ChefSpec::Matchers::RenderFileMatcher do
4
+ let(:path) { '/tmp/thing' }
5
+ let(:file) { double('file', to: path, to_s: "file[#{path}]", performed_action?: true) }
6
+ let(:chef_run) { double('chef run', find_resource: file) }
7
+ subject { described_class.new(path) }
8
+
9
+ describe '#with_content' do
10
+ it 'accepts do/end syntax' do
11
+ subject.matches?(chef_run)
12
+ expect(
13
+ subject.with_content do |content|
14
+ 'Does not raise ArgumentError'
15
+ end.expected_content.first.call
16
+ ).to eq('Does not raise ArgumentError')
17
+ end
18
+ end
19
+
20
+ describe '#failure_message' do
21
+ it 'has the right value' do
22
+ subject.matches?(chef_run)
23
+ expect(subject.failure_message)
24
+ .to eq(%Q(expected Chef run to render "#{path}"))
25
+ end
26
+ end
27
+
28
+ describe '#failure_message_when_negated' do
29
+ it 'has the right value' do
30
+ subject.matches?(chef_run)
31
+ expect(subject.failure_message_when_negated)
32
+ .to eq(%Q(expected file "#{path}" to not be in Chef run))
33
+ end
34
+ end
35
+
36
+ describe '#description' do
37
+ it 'has the right value' do
38
+ subject.matches?(chef_run)
39
+ expect(subject.description).to eq(%Q(render file "#{path}"))
40
+ end
41
+
42
+ it 'has the right value when with_content is chained' do
43
+ subject.matches?(chef_run)
44
+ expect(
45
+ subject.with_content('foo').with_content('bar').description
46
+ ).to eq(%Q(render file "#{path}" with content "foo" with content "bar"))
47
+ end
48
+ end
49
+
50
+ context 'when the file is correct' do
51
+ it 'matches' do
52
+ expect(subject.matches?(chef_run)).to be_truthy
53
+ end
54
+
55
+ it 'adds the resource to the coverage report' do
56
+ expect(ChefSpec::Coverage).to receive(:cover!).with(file)
57
+ subject.matches?(chef_run)
58
+ end
59
+ end
60
+
61
+ context 'when the file is not correct' do
62
+ it 'does not match' do
63
+ allow(chef_run).to receive(:find_resource).and_return(nil)
64
+ failure = described_class.new('nope')
65
+ expect(failure.matches?(chef_run)).to be_falsy
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe ChefSpec::Matchers::ResourceMatcher do
4
+ pending
5
+ end
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+
3
+ describe ChefSpec::Matchers::StateAttrsMatcher do
4
+ subject { described_class.new([:a, :b]) }
5
+
6
+ context 'when the resource does not exist' do
7
+ let(:resource) { nil }
8
+ before { subject.matches?(resource) }
9
+
10
+ it 'does not match' do
11
+ expect(subject).to_not be_matches(resource)
12
+ end
13
+
14
+ it 'has the correct description' do
15
+ expect(subject.description).to eq('have state attributes [:a, :b]')
16
+ end
17
+
18
+ it 'has the correct failure message for should' do
19
+ expect(subject.failure_message).to include <<-EOH.gsub(/^ {8}/, '')
20
+ expected _something_ to have state attributes, but the _something_ you gave me was nil!
21
+ Ensure the resource exists before making assertions:
22
+
23
+ expect(resource).to be
24
+ EOH
25
+ end
26
+
27
+ it 'has the correct failure message for should not' do
28
+ expect(subject.failure_message_when_negated).to include <<-EOH.gsub(/^ {8}/, '')
29
+ expected _something_ to not have state attributes, but the _something_ you gave me was nil!
30
+ Ensure the resource exists before making assertions:
31
+
32
+ expect(resource).to be
33
+ EOH
34
+ end
35
+ end
36
+
37
+ context 'when the resource exists' do
38
+ let(:klass) { double('class', state_attrs: [:a, :b]) }
39
+ let(:resource) { double('resource', class: klass) }
40
+ before { subject.matches?(resource) }
41
+
42
+ it 'has the correct description' do
43
+ expect(subject.description).to eq('have state attributes [:a, :b]')
44
+ end
45
+
46
+ it 'has the correct failure message for should' do
47
+ expect(subject.failure_message).to eq('expected [:a, :b] to equal [:a, :b]')
48
+ end
49
+
50
+ it 'has the correct failure message for should not' do
51
+ expect(subject.failure_message_when_negated).to eq('expected [:a, :b] to not equal [:a, :b]')
52
+ end
53
+
54
+ it 'matches when the state attributes are correct' do
55
+ expect(subject).to be_matches(resource)
56
+ end
57
+
58
+ it 'does not match when the state attributes are incorrect' do
59
+ allow(klass).to receive(:state_attrs).and_return([:c, :d])
60
+ expect(subject).to_not be_matches(resource)
61
+ end
62
+
63
+ it 'does not match when partial state attribute are incorrect' do
64
+ allow(klass).to receive(:state_attrs).and_return([:b, :c])
65
+ expect(subject).to_not be_matches(resource)
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ describe ChefSpec::Matchers::SubscribesMatcher do
4
+ subject { described_class.new('execute[install]') }
5
+ let(:runner) { double('runner', find_resource: nil) }
6
+ let(:run_context) { double('run_context', node: node) }
7
+ let(:node) { double('node', runner: runner) }
8
+ let(:package) do
9
+ double('package',
10
+ name: 'package',
11
+ to_s: 'package[foo]',
12
+ run_context: run_context,
13
+ )
14
+ end
15
+
16
+ context 'when no resource is found' do
17
+ describe '#failure_message' do
18
+ it 'has the right value' do
19
+ subject.matches?(package)
20
+ expect(subject.failure_message)
21
+ .to include %|expected _something_ to notify "package[foo]", but the _something_ you gave me was nil! If you are running a test like:|
22
+ end
23
+ end
24
+ end
25
+
26
+ context 'when the resource exists' do
27
+ let(:execute) do
28
+ double('execute',
29
+ name: 'execute',
30
+ to_s: 'execute[install]',
31
+ immediate_notifications: [],
32
+ delayed_notifications: [],
33
+ before_notifications: []
34
+ )
35
+ end
36
+
37
+ before do
38
+ allow(runner).to receive(:find_resource).and_return(execute)
39
+ end
40
+
41
+ describe '#failure_message' do
42
+ it 'has the right value' do
43
+ subject.matches?(package)
44
+ expect(subject.failure_message)
45
+ .to include %|expected "execute[install]" to notify "package[foo]", but did not.|
46
+ end
47
+ end
48
+
49
+ describe '#failure_message_when_negated' do
50
+ it 'has the right value' do
51
+ subject.matches?(package)
52
+ expect(subject.failure_message_when_negated)
53
+ .to eq %|expected "execute[install]" to not notify "package[foo]", but it did.|
54
+ end
55
+ end
56
+ end
57
+
58
+ describe '#description' do
59
+ it 'has the right value' do
60
+ subject.matches?(package)
61
+ expect(subject.description)
62
+ .to eq %|notify "package[foo]"|
63
+ end
64
+ end
65
+ end