1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
|
require 'spec_helper'
require 'chef/recipe'
# The goal of these tests is to make sure that loading resources from a file creates the necessary notifications.
# Then once converge has started, both immediate and delayed notifications are called as the resources are converged.
# We want to do this WITHOUT actually converging any resources - we don't want to take time changing the system,
# we just want to make sure the run_context, the notification DSL and the converge hooks are working together
# to perform notifications.
# This test is extremely fragile since it mocks MANY different systems at once - any of them changes, this test
# breaks
describe "Notifications" do
# We always pretend we are on OSx because that has a specific provider (HomebrewProvider) so it
# tests the translation from Provider => HomebrewProvider
let(:node) {
n = Chef::Node.new
n.override[:os] = "darwin"
n
}
let(:cookbook_collection) { double("Chef::CookbookCollection").as_null_object }
let(:events) { double("Chef::EventDispatch::Dispatcher").as_null_object }
let(:run_context) { Chef::RunContext.new(node, cookbook_collection, events) }
let(:recipe) { Chef::Recipe.new("notif", "test", run_context) }
let(:runner) { Chef::Runner.new(run_context) }
before do
# By default, every provider will do nothing
p = Chef::Provider.new(nil, run_context)
allow_any_instance_of(Chef::Resource).to receive(:provider_for_action).and_return(p)
allow(p).to receive(:run_action)
end
it "should subscribe from one resource to another" do
log_resource = recipe.declare_resource(:log, "subscribed-log") do
message "This is a log message"
action :nothing
subscribes :write, "package[vim]", :immediately
end
package_resource = recipe.declare_resource(:package, "vim") do
action :install
end
expect(log_resource).to receive(:run_action).with(:nothing, nil, nil).and_call_original
expect(package_resource).to receive(:run_action).with(:install, nil, nil).and_call_original
update_action(package_resource)
expect(log_resource).to receive(:run_action).with(:write, :immediate, package_resource).and_call_original
runner.converge
end
it "should notify from one resource to another immediately" do
log_resource = recipe.declare_resource(:log, "log") do
message "This is a log message"
action :write
notifies :install, "package[vim]", :immediately
end
package_resource = recipe.declare_resource(:package, "vim") do
action :nothing
end
expect(log_resource).to receive(:run_action).with(:write, nil, nil).and_call_original
update_action(log_resource)
expect(package_resource).to receive(:run_action).with(:install, :immediate, log_resource).ordered.and_call_original
expect(package_resource).to receive(:run_action).with(:nothing, nil, nil).ordered.and_call_original
runner.converge
end
it "should notify from one resource to another delayed" do
log_resource = recipe.declare_resource(:log, "log") do
message "This is a log message"
action :write
notifies :install, "package[vim]", :delayed
end
package_resource = recipe.declare_resource(:package, "vim") do
action :nothing
end
expect(log_resource).to receive(:run_action).with(:write, nil, nil).and_call_original
update_action(log_resource)
expect(package_resource).to receive(:run_action).with(:nothing, nil, nil).ordered.and_call_original
expect(package_resource).to receive(:run_action).with(:install, :delayed, nil).ordered.and_call_original
runner.converge
end
describe "when one resource is defined lazily" do
it "subscribes to a resource defined in a ruby block" do
r = recipe
t = self
ruby_block = recipe.declare_resource(:ruby_block, "rblock") do
block do
log_resource = r.declare_resource(:log, "log") do
message "This is a log message"
action :write
end
t.expect(log_resource).to t.receive(:run_action).with(:write, nil, nil).and_call_original
t.update_action(log_resource)
end
end
package_resource = recipe.declare_resource(:package, "vim") do
action :nothing
subscribes :install, "log[log]", :delayed
end
# RubyBlock needs to be able to run for our lazy examples to work - and it alone cannot affect the system
expect(ruby_block).to receive(:provider_for_action).and_call_original
expect(package_resource).to receive(:run_action).with(:nothing, nil, nil).ordered.and_call_original
expect(package_resource).to receive(:run_action).with(:install, :delayed, nil).ordered.and_call_original
runner.converge
end
it "notifies from inside a ruby_block to a resource defined outside" do
r = recipe
t = self
ruby_block = recipe.declare_resource(:ruby_block, "rblock") do
block do
log_resource = r.declare_resource(:log, "log") do
message "This is a log message"
action :write
notifies :install, "package[vim]", :immediately
end
t.expect(log_resource).to t.receive(:run_action).with(:write, nil, nil).and_call_original
t.update_action(log_resource)
end
end
package_resource = recipe.declare_resource(:package, "vim") do
action :nothing
end
# RubyBlock needs to be able to run for our lazy examples to work - and it alone cannot affect the system
expect(ruby_block).to receive(:provider_for_action).and_call_original
expect(package_resource).to receive(:run_action).with(:install, :immediate, instance_of(Chef::Resource::Log)).ordered.and_call_original
expect(package_resource).to receive(:run_action).with(:nothing, nil, nil).ordered.and_call_original
runner.converge
end
end
# Mocks having the provider run successfully and update the resource
def update_action(resource)
p = Chef::Provider.new(resource, run_context)
expect(resource).to receive(:provider_for_action).and_return(p)
expect(p).to receive(:run_action) {
resource.updated_by_last_action(true)
}
end
end
|