puppet 6.0.2-x64-mingw32 → 6.0.3-x64-mingw32
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puppet might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Gemfile +2 -2
- data/Gemfile.lock +11 -11
- data/lib/puppet/application.rb +5 -0
- data/lib/puppet/application/apply.rb +1 -0
- data/lib/puppet/application/script.rb +1 -1
- data/lib/puppet/application/ssl.rb +119 -49
- data/lib/puppet/defaults.rb +9 -27
- data/lib/puppet/face/node/clean.rb +0 -1
- data/lib/puppet/feature/base.rb +1 -1
- data/lib/puppet/file_serving/fileset.rb +1 -1
- data/lib/puppet/pops/validation/checker4_0.rb +4 -2
- data/lib/puppet/provider/package/windows.rb +2 -2
- data/lib/puppet/provider/package/windows/exe_package.rb +3 -10
- data/lib/puppet/provider/service/windows.rb +11 -3
- data/lib/puppet/provider/user/useradd.rb +2 -10
- data/lib/puppet/resource/catalog.rb +1 -5
- data/lib/puppet/ssl/host.rb +7 -9
- data/lib/puppet/transaction/persistence.rb +1 -1
- data/lib/puppet/type/package.rb +1 -1
- data/lib/puppet/type/user.rb +4 -1
- data/lib/puppet/util.rb +7 -3
- data/lib/puppet/util/execution.rb +1 -0
- data/lib/puppet/util/logging.rb +3 -2
- data/lib/puppet/util/windows/process.rb +6 -2
- data/lib/puppet/util/windows/security.rb +14 -0
- data/lib/puppet/util/windows/service.rb +217 -74
- data/lib/puppet/util/windows/user.rb +3 -5
- data/lib/puppet/version.rb +1 -1
- data/locales/ja/puppet.po +505 -276
- data/locales/puppet.pot +250 -111
- data/man/man5/puppet.conf.5 +8 -1
- data/man/man8/puppet-ssl.8 +22 -2
- data/man/man8/puppet.8 +1 -1
- data/spec/integration/parser/collection_spec.rb +4 -8
- data/spec/integration/type/file_spec.rb +6 -6
- data/spec/integration/util/windows/security_spec.rb +10 -7
- data/spec/integration/util/windows/user_spec.rb +37 -17
- data/spec/lib/puppet/test_ca.rb +1 -1
- data/spec/unit/agent_spec.rb +2 -2
- data/spec/unit/application/apply_spec.rb +41 -2
- data/spec/unit/application/face_base_spec.rb +1 -1
- data/spec/unit/application/ssl_spec.rb +160 -110
- data/spec/unit/application_spec.rb +29 -11
- data/spec/unit/configurer/downloader_spec.rb +1 -1
- data/spec/unit/configurer_spec.rb +5 -5
- data/spec/unit/face/node_spec.rb +1 -3
- data/spec/unit/file_serving/fileset_spec.rb +11 -11
- data/spec/unit/network/http/connection_spec.rb +2 -2
- data/spec/unit/pops/validator/validator_spec.rb +24 -10
- data/spec/unit/provider/package/windows/exe_package_spec.rb +3 -3
- data/spec/unit/provider/package/windows_spec.rb +4 -4
- data/spec/unit/provider/service/windows_spec.rb +21 -3
- data/spec/unit/provider/user/useradd_spec.rb +2 -2
- data/spec/unit/resource/catalog_spec.rb +2 -2
- data/spec/unit/ssl/host_spec.rb +1 -1
- data/spec/unit/transaction/persistence_spec.rb +4 -4
- data/spec/unit/util/execution_spec.rb +19 -1
- data/spec/unit/util/logging_spec.rb +58 -0
- data/spec/unit/util/windows/service_spec.rb +344 -191
- metadata +2 -2
@@ -168,11 +168,29 @@ describe Puppet::Util::Execution, if: !Puppet::Util::Platform.jruby? do
|
|
168
168
|
},
|
169
169
|
:close_handles => false
|
170
170
|
)
|
171
|
-
|
171
|
+
|
172
172
|
call_exec_windows('test command', { :cwd => cwd }, @stdin, @stdout, @stderr)
|
173
173
|
end
|
174
174
|
end
|
175
175
|
|
176
|
+
context 'suppress_window option' do
|
177
|
+
let(:cwd) { 'cwd' }
|
178
|
+
it "should execute the command in the specified working directory" do
|
179
|
+
Process.expects(:create).with(
|
180
|
+
:command_line => "test command",
|
181
|
+
:startup_info => {
|
182
|
+
:stdin => @stdin,
|
183
|
+
:stdout => @stdout,
|
184
|
+
:stderr => @stderr
|
185
|
+
},
|
186
|
+
:close_handles => false,
|
187
|
+
:creation_flags => Puppet::Util::Windows::Process::CREATE_NO_WINDOW
|
188
|
+
)
|
189
|
+
|
190
|
+
call_exec_windows('test command', { :suppress_window => true }, @stdin, @stdout, @stderr)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
176
194
|
it "should return the process info of the child process" do
|
177
195
|
expect(call_exec_windows('test command', {}, @stdin, @stdout, @stderr)).to eq(proc_info_stub)
|
178
196
|
end
|
@@ -99,6 +99,64 @@ describe Puppet::Util::Logging do
|
|
99
99
|
end
|
100
100
|
end
|
101
101
|
|
102
|
+
describe "log_exception" do
|
103
|
+
context "when requesting a debug level it is logged at debug" do
|
104
|
+
it "the exception is a ParseErrorWithIssue and message is :default" do
|
105
|
+
Puppet::Util::Log.expects(:create).with do |args|
|
106
|
+
expect(args[:message]).to eq("Test")
|
107
|
+
expect(args[:level]).to eq(:debug)
|
108
|
+
end
|
109
|
+
|
110
|
+
begin
|
111
|
+
raise Puppet::ParseErrorWithIssue, "Test"
|
112
|
+
rescue Puppet::ParseErrorWithIssue => err
|
113
|
+
Puppet.log_exception(err, :default, level: :debug)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
it "the exception is something else" do
|
118
|
+
Puppet::Util::Log.expects(:create).with do |args|
|
119
|
+
expect(args[:message]).to eq("Test")
|
120
|
+
expect(args[:level]).to eq(:debug)
|
121
|
+
end
|
122
|
+
|
123
|
+
begin
|
124
|
+
raise Puppet::Error, "Test"
|
125
|
+
rescue Puppet::Error => err
|
126
|
+
Puppet.log_exception(err, :default, level: :debug)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context "no log level is requested it defaults to err" do
|
132
|
+
it "the exception is a ParseErrorWithIssue and message is :default" do
|
133
|
+
Puppet::Util::Log.expects(:create).with do |args|
|
134
|
+
expect(args[:message]).to eq("Test")
|
135
|
+
expect(args[:level]).to eq(:err)
|
136
|
+
end
|
137
|
+
|
138
|
+
begin
|
139
|
+
raise Puppet::ParseErrorWithIssue, "Test"
|
140
|
+
rescue Puppet::ParseErrorWithIssue => err
|
141
|
+
Puppet.log_exception(err)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
it "the exception is something else" do
|
146
|
+
Puppet::Util::Log.expects(:create).with do |args|
|
147
|
+
expect(args[:message]).to eq("Test")
|
148
|
+
expect(args[:level]).to eq(:err)
|
149
|
+
end
|
150
|
+
|
151
|
+
begin
|
152
|
+
raise Puppet::Error, "Test"
|
153
|
+
rescue Puppet::Error => err
|
154
|
+
Puppet.log_exception(err)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
102
160
|
describe "when sending a deprecation warning" do
|
103
161
|
it "does not log a message when deprecation warnings are disabled" do
|
104
162
|
Puppet.expects(:[]).with(:disable_warnings).returns %w[deprecations]
|
@@ -10,6 +10,10 @@ describe "Puppet::Util::Windows::Service", :if => Puppet.features.microsoft_wind
|
|
10
10
|
.returns("fake error!")
|
11
11
|
end
|
12
12
|
|
13
|
+
def service_state_str(state)
|
14
|
+
Puppet::Util::Windows::Service::SERVICE_STATES[state].to_s
|
15
|
+
end
|
16
|
+
|
13
17
|
# The following should emulate a successful call to the private function
|
14
18
|
# query_status that returns the value of query_return. This should give
|
15
19
|
# us a way to mock changes in service status.
|
@@ -21,6 +25,12 @@ describe "Puppet::Util::Windows::Service", :if => Puppet.features.microsoft_wind
|
|
21
25
|
subject::SERVICE_STATUS_PROCESS.expects(:new).in_sequence(status_checks).returns(query_return)
|
22
26
|
end
|
23
27
|
|
28
|
+
def expect_successful_status_queries_and_return(*query_returns)
|
29
|
+
query_returns.each do |query_return|
|
30
|
+
expect_successful_status_query_and_return(query_return)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
24
34
|
# The following should emulate a successful call to the private function
|
25
35
|
# query_config that returns the value of query_return. This should give
|
26
36
|
# us a way to mock changes in service configuration.
|
@@ -42,8 +52,6 @@ describe "Puppet::Util::Windows::Service", :if => Puppet.features.microsoft_wind
|
|
42
52
|
before do
|
43
53
|
subject.stubs(:QueryServiceStatusEx).returns(1)
|
44
54
|
subject.stubs(:QueryServiceConfigW).returns(1)
|
45
|
-
subject.stubs(:StartServiceW).returns(1)
|
46
|
-
subject.stubs(:ControlService).returns(1)
|
47
55
|
subject.stubs(:ChangeServiceConfigW).returns(1)
|
48
56
|
subject.stubs(:OpenSCManagerW).returns(scm)
|
49
57
|
subject.stubs(:OpenServiceW).returns(service)
|
@@ -90,262 +98,407 @@ describe "Puppet::Util::Windows::Service", :if => Puppet.features.microsoft_wind
|
|
90
98
|
end
|
91
99
|
end
|
92
100
|
|
93
|
-
|
101
|
+
# This shared example contains the unit tests for the wait_on_pending_state
|
102
|
+
# helper as used by service actions like #start and #stop. Before including
|
103
|
+
# this shared example, be sure to mock out any intermediate calls prior to
|
104
|
+
# the pending transition, and make sure that the post-condition _after_ those
|
105
|
+
# intermediate calls leaves the service in the pending state. Before including
|
106
|
+
# this example in your tests, be sure to define the following variables in a `let`
|
107
|
+
# context:
|
108
|
+
# * action -- The service action
|
109
|
+
shared_examples "a service action waiting on a pending transition" do |pending_state|
|
110
|
+
pending_state_str = Puppet::Util::Windows::Service::SERVICE_STATES[pending_state].to_s
|
94
111
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
112
|
+
final_state = Puppet::Util::Windows::Service::FINAL_STATES[pending_state]
|
113
|
+
final_state_str = Puppet::Util::Windows::Service::SERVICE_STATES[final_state].to_s
|
114
|
+
|
115
|
+
it "raises a Puppet::Error if the service query fails" do
|
116
|
+
subject.expects(:QueryServiceStatusEx).in_sequence(status_checks).returns(FFI::WIN32_FALSE)
|
117
|
+
|
118
|
+
expect { subject.send(action, mock_service_name) }.to raise_error(Puppet::Error)
|
100
119
|
end
|
101
120
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
121
|
+
it "raises a Puppet::Error if the service unexpectedly transitions to a state other than #{pending_state_str} or #{final_state_str}" do
|
122
|
+
invalid_state = (subject::SERVICE_STATES.keys - [pending_state, final_state]).first
|
123
|
+
|
124
|
+
expect_successful_status_query_and_return(dwCurrentState: invalid_state)
|
125
|
+
|
126
|
+
expect { subject.send(action, mock_service_name) }.to raise_error(Puppet::Error)
|
127
|
+
end
|
128
|
+
|
129
|
+
it "waits for at least 1 second if the wait_hint/10 is < 1 second" do
|
130
|
+
expect_successful_status_queries_and_return(
|
131
|
+
{ :dwCurrentState => pending_state, :dwWaitHint => 0, :dwCheckPoint => 1 },
|
132
|
+
{ :dwCurrentState => final_state }
|
133
|
+
)
|
134
|
+
|
135
|
+
subject.expects(:sleep).with(1)
|
136
|
+
|
137
|
+
subject.send(action, mock_service_name)
|
138
|
+
end
|
139
|
+
|
140
|
+
it "waits for at most 10 seconds if wait_hint/10 is > 10 seconds" do
|
141
|
+
expect_successful_status_queries_and_return(
|
142
|
+
{ :dwCurrentState => pending_state, :dwWaitHint => 1000000, :dwCheckPoint => 1 },
|
143
|
+
{ :dwCurrentState => final_state }
|
144
|
+
)
|
145
|
+
|
146
|
+
subject.expects(:sleep).with(10)
|
147
|
+
|
148
|
+
subject.send(action, mock_service_name)
|
149
|
+
end
|
150
|
+
|
151
|
+
it "does not raise an error if the service makes any progress while transitioning to #{final_state_str}" do
|
152
|
+
expect_successful_status_queries_and_return(
|
153
|
+
# The three "pending_state" statuses simulate the scenario where the service
|
154
|
+
# makes some progress during the transition right when Puppet's about to
|
155
|
+
# time out.
|
156
|
+
{ :dwCurrentState => pending_state, :dwWaitHint => 100000, :dwCheckPoint => 1 },
|
157
|
+
{ :dwCurrentState => pending_state, :dwWaitHint => 100000, :dwCheckPoint => 1 },
|
158
|
+
{ :dwCurrentState => pending_state, :dwWaitHint => 100000, :dwCheckPoint => 2 },
|
159
|
+
|
160
|
+
{ :dwCurrentState => final_state }
|
161
|
+
)
|
162
|
+
|
163
|
+
expect { subject.send(action, mock_service_name) }.to_not raise_error
|
107
164
|
end
|
108
165
|
|
109
|
-
|
110
|
-
|
111
|
-
expect_successful_status_query_and_return(
|
166
|
+
it "raises a Puppet::Error if it times out while waiting for the transition to #{final_state_str}" do
|
167
|
+
31.times do
|
168
|
+
expect_successful_status_query_and_return(
|
169
|
+
dwCurrentState: pending_state,
|
170
|
+
dwWaitHint: 10000,
|
171
|
+
dwCheckPoint: 1
|
172
|
+
)
|
112
173
|
end
|
113
174
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
175
|
+
expect { subject.send(action, mock_service_name) }.to raise_error(Puppet::Error)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# This shared example contains the unit tests for the transition_service_state
|
180
|
+
# helper, which is the helper that all of our service actions like #start, #stop
|
181
|
+
# delegate to. Including these tests under a shared example lets us include them in each of
|
182
|
+
# those service action's unit tests. Before including this example in your tests, be
|
183
|
+
# sure to define the following variables in a `let` context:
|
184
|
+
# * initial_state -- The initial state of the service prior to performing the state
|
185
|
+
# transition
|
186
|
+
#
|
187
|
+
# * mock_state_transition -- A lambda that mocks the state transition. This should mock
|
188
|
+
# any code in the block that's passed to the
|
189
|
+
# transition_service_state helper
|
190
|
+
#
|
191
|
+
# See the unit tests for the #start method to see how this shared example's
|
192
|
+
# included.
|
193
|
+
#
|
194
|
+
shared_examples "a service action that transitions the service state" do |action, valid_initial_states, pending_state, final_state|
|
195
|
+
valid_initial_states_str = valid_initial_states.map do |state|
|
196
|
+
Puppet::Util::Windows::Service::SERVICE_STATES[state]
|
197
|
+
end.join(', ')
|
198
|
+
pending_state_str = Puppet::Util::Windows::Service::SERVICE_STATES[pending_state].to_s
|
199
|
+
final_state_str = Puppet::Util::Windows::Service::SERVICE_STATES[final_state].to_s
|
200
|
+
|
201
|
+
it "noops if the service is already in the #{final_state} state" do
|
202
|
+
expect_successful_status_query_and_return(dwCurrentState: final_state)
|
203
|
+
|
204
|
+
expect { subject.send(action, mock_service_name) }.to_not raise_error
|
205
|
+
end
|
206
|
+
|
207
|
+
# invalid_initial_states will be empty for the #stop action
|
208
|
+
invalid_initial_states = Puppet::Util::Windows::Service::SERVICE_STATES.keys - valid_initial_states - [final_state]
|
209
|
+
unless invalid_initial_states.empty?
|
210
|
+
it "raises a Puppet::Error if the service's initial state is not one of #{valid_initial_states_str}" do
|
211
|
+
invalid_initial_state = invalid_initial_states.first
|
212
|
+
expect_successful_status_query_and_return(dwCurrentState: invalid_initial_state)
|
213
|
+
|
214
|
+
expect{ subject.send(action, mock_service_name) }.to raise_error(Puppet::Error)
|
118
215
|
end
|
216
|
+
end
|
119
217
|
|
120
|
-
|
121
|
-
|
122
|
-
|
218
|
+
context "when there's a pending transition to the #{final_state} state" do
|
219
|
+
before(:each) do
|
220
|
+
expect_successful_status_query_and_return(dwCurrentState: pending_state)
|
123
221
|
end
|
124
222
|
|
125
|
-
|
126
|
-
|
127
|
-
expect{ subject.start(mock_service_name) }.to raise_error(Puppet::Error)
|
223
|
+
include_examples "a service action waiting on a pending transition", pending_state do
|
224
|
+
let(:action) { action }
|
128
225
|
end
|
129
226
|
end
|
130
227
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
228
|
+
# If the service action accepts an unsafe pending state as one of the service's
|
229
|
+
# initial states, then we need to test that the action waits for the service to
|
230
|
+
# transition from that unsafe pending state before doing anything else.
|
231
|
+
unsafe_pending_states = valid_initial_states & Puppet::Util::Windows::Service::UNSAFE_PENDING_STATES
|
232
|
+
unless unsafe_pending_states.empty?
|
233
|
+
unsafe_pending_state = unsafe_pending_states.first
|
234
|
+
unsafe_pending_state_str = Puppet::Util::Windows::Service::SERVICE_STATES[unsafe_pending_state]
|
235
|
+
|
236
|
+
context "waiting for a service with #{unsafe_pending_state_str} as its initial state" do
|
237
|
+
before(:each) do
|
238
|
+
# This mocks the status query to return the 'final_state' by default. Otherwise,
|
239
|
+
# we will fail the tests in the latter parts of the code where we wait for the
|
240
|
+
# service to finish transitioning to the 'final_state'.
|
241
|
+
subject::SERVICE_STATUS_PROCESS.stubs(:new).returns(dwCurrentState: final_state)
|
242
|
+
|
243
|
+
# Set our service's initial state
|
244
|
+
expect_successful_status_query_and_return(dwCurrentState: unsafe_pending_state)
|
245
|
+
|
246
|
+
mock_state_transition.call
|
247
|
+
end
|
142
248
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOPPED})
|
147
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_RUNNING})
|
148
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_RUNNING})
|
149
|
-
subject.expects(:sleep).with(1)
|
150
|
-
subject.start(mock_service_name)
|
249
|
+
include_examples "a service action waiting on a pending transition", unsafe_pending_state do
|
250
|
+
let(:action) { action }
|
251
|
+
end
|
151
252
|
end
|
253
|
+
end
|
152
254
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
255
|
+
# reads e.g. "waiting for the service to transition to the SERVICE_RUNNING state after executing the 'start' action"
|
256
|
+
#
|
257
|
+
# NOTE: This is really unit testing the wait_on_state_transition helper
|
258
|
+
context "waiting for the service to transition to the #{final_state_str} state after executing the '#{action}' action" do
|
259
|
+
before(:each) do
|
260
|
+
# Set our service's initial state prior to performing the state transition
|
261
|
+
expect_successful_status_query_and_return(dwCurrentState: initial_state)
|
262
|
+
|
263
|
+
mock_state_transition.call
|
161
264
|
end
|
162
265
|
|
163
|
-
it "raises a
|
164
|
-
subject.expects(:QueryServiceStatusEx).in_sequence(status_checks).returns(1)
|
266
|
+
it "raises a Puppet::Error if the service query fails" do
|
165
267
|
subject.expects(:QueryServiceStatusEx).in_sequence(status_checks).returns(FFI::WIN32_FALSE)
|
166
|
-
expect{subject.start(mock_service_name)}.to raise_error(Puppet::Error)
|
167
|
-
end
|
168
|
-
|
169
|
-
it "Does not raise an error if the service makes progress" do
|
170
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOP_PENDING, :dwWaitHint => 0, :dwCheckPoint => 0})
|
171
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOP_PENDING, :dwWaitHint => 0, :dwCheckPoint => 0})
|
172
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOP_PENDING, :dwWaitHint => 0, :dwCheckPoint => 2})
|
173
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOP_PENDING, :dwWaitHint => 0, :dwCheckPoint => 30})
|
174
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOP_PENDING, :dwWaitHint => 0, :dwCheckPoint => 50})
|
175
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOP_PENDING, :dwWaitHint => 0, :dwCheckPoint => 98})
|
176
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOPPED})
|
177
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_RUNNING})
|
178
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_RUNNING})
|
179
|
-
expect{subject.start(mock_service_name)}.to_not raise_error
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
context "when the service ends up still in STOPPED:" do
|
184
|
-
it "waits, then queries again until RUNNING" do
|
185
|
-
# these will be before the call to controlService
|
186
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOPPED})
|
187
|
-
# everything from here on will be _after_ the call to ControlService
|
188
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOPPED})
|
189
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_START_PENDING, :dwWaitHint => 30000, :dwCheckPoint => 1})
|
190
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_START_PENDING, :dwWaitHint => 30000, :dwCheckPoint => 50})
|
191
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_RUNNING})
|
192
|
-
subject.start(mock_service_name)
|
193
|
-
end
|
194
268
|
|
195
|
-
|
196
|
-
# these will be before the call to controlService
|
197
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOPPED})
|
198
|
-
# the number of times here is a little strange: there are 31 status queries sleeps because there will be a 31st query
|
199
|
-
# that is the final query where the command has reached the wait hint and it's time to error
|
200
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOPPED}).times(31)
|
201
|
-
subject.expects(:sleep).times(30).with(1)
|
202
|
-
expect{subject.start(mock_service_name)}.to raise_error(Puppet::Error)
|
269
|
+
expect { subject.send(action, mock_service_name) }.to raise_error(Puppet::Error)
|
203
270
|
end
|
204
|
-
end
|
205
271
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
272
|
+
it "waits, then queries again until it transitions to #{final_state_str}" do
|
273
|
+
expect_successful_status_queries_and_return(
|
274
|
+
{ :dwCurrentState => initial_state },
|
275
|
+
{ :dwCurrentState => initial_state },
|
276
|
+
{ :dwCurrentState => final_state }
|
277
|
+
)
|
278
|
+
|
279
|
+
subject.expects(:sleep).with(1).twice
|
280
|
+
|
281
|
+
subject.send(action, mock_service_name)
|
210
282
|
end
|
211
283
|
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
284
|
+
context "when it transitions to the #{pending_state_str} state" do
|
285
|
+
before(:each) do
|
286
|
+
expect_successful_status_query_and_return(dwCurrentState: pending_state)
|
287
|
+
end
|
288
|
+
|
289
|
+
include_examples "a service action waiting on a pending transition", pending_state do
|
290
|
+
let(:action) { action }
|
291
|
+
end
|
217
292
|
end
|
218
293
|
|
219
|
-
it "
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
subject.
|
225
|
-
subject.start(mock_service_name)
|
294
|
+
it "raises a Puppet::Error if it times out while waiting for the transition to #{final_state_str}" do
|
295
|
+
31.times do
|
296
|
+
expect_successful_status_query_and_return(dwCurrentState: initial_state)
|
297
|
+
end
|
298
|
+
|
299
|
+
expect { subject.send(action, mock_service_name) }.to raise_error(Puppet::Error)
|
226
300
|
end
|
301
|
+
end
|
302
|
+
end
|
227
303
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
304
|
+
describe "#start" do
|
305
|
+
# rspec will still try to load the tests even though
|
306
|
+
# the :if => Puppet.features.microsoft_windows? filter
|
307
|
+
# is passed-in to the top-level describe block on
|
308
|
+
# non-Windows platforms; it just won't run them. However
|
309
|
+
# on these platforms, the loading will fail because this
|
310
|
+
# test uses a shared example that references variables
|
311
|
+
# from the Windows::Service module when building the unit
|
312
|
+
# tests, which is only available on Windows platforms.
|
313
|
+
# Thus, we add the next here to ensure that rspec does not
|
314
|
+
# attempt to load our test code. This is OK for us to do
|
315
|
+
# because we do not want to run these tests on non-Windows
|
316
|
+
# platforms.
|
317
|
+
next unless Puppet.features.microsoft_windows?
|
318
|
+
|
319
|
+
context "when the service control manager cannot be opened" do
|
320
|
+
let(:scm) { FFI::Pointer::NULL_HANDLE }
|
321
|
+
it "raises a puppet error" do
|
322
|
+
expect{ subject.start(mock_service_name) }.to raise_error(Puppet::Error)
|
235
323
|
end
|
324
|
+
end
|
236
325
|
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
subject.expects(:sleep).times(30).with(1)
|
242
|
-
expect{subject.start(mock_service_name)}.to raise_error(Puppet::Error)
|
326
|
+
context "when the service cannot be opened" do
|
327
|
+
let(:service) { FFI::Pointer::NULL_HANDLE }
|
328
|
+
it "raises a puppet error" do
|
329
|
+
expect{ subject.start(mock_service_name) }.to raise_error(Puppet::Error)
|
243
330
|
end
|
331
|
+
end
|
244
332
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
333
|
+
context "when the service can be opened" do
|
334
|
+
# Can't use rspec's subject here because that
|
335
|
+
# can only be referenced inside an 'it' block.
|
336
|
+
service = Puppet::Util::Windows::Service
|
337
|
+
valid_initial_states = [
|
338
|
+
service::SERVICE_STOP_PENDING,
|
339
|
+
service::SERVICE_STOPPED,
|
340
|
+
service::SERVICE_START_PENDING
|
341
|
+
]
|
342
|
+
final_state = service::SERVICE_RUNNING
|
343
|
+
|
344
|
+
include_examples "a service action that transitions the service state", :start, valid_initial_states, service::SERVICE_START_PENDING, final_state do
|
345
|
+
let(:initial_state) { subject::SERVICE_STOPPED }
|
346
|
+
let(:mock_state_transition) do
|
347
|
+
lambda do
|
348
|
+
subject.stubs(:StartServiceW).returns(1)
|
349
|
+
end
|
350
|
+
end
|
251
351
|
end
|
352
|
+
|
353
|
+
it "raises a Puppet::Error if StartServiceW returns false" do
|
354
|
+
expect_successful_status_query_and_return(dwCurrentState: subject::SERVICE_STOPPED)
|
355
|
+
|
356
|
+
subject.expects(:StartServiceW).returns(FFI::WIN32_FALSE)
|
252
357
|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
subject.expects(:
|
263
|
-
|
358
|
+
expect { subject.start(mock_service_name) }.to raise_error(Puppet::Error)
|
359
|
+
end
|
360
|
+
|
361
|
+
it "starts the service" do
|
362
|
+
expect_successful_status_queries_and_return(
|
363
|
+
{ dwCurrentState: subject::SERVICE_STOPPED },
|
364
|
+
{ dwCurrentState: subject::SERVICE_RUNNING }
|
365
|
+
)
|
366
|
+
|
367
|
+
subject.expects(:StartServiceW).returns(1)
|
368
|
+
|
369
|
+
subject.start(mock_service_name)
|
264
370
|
end
|
265
371
|
end
|
266
372
|
end
|
267
373
|
|
268
374
|
describe "#stop" do
|
375
|
+
next unless Puppet.features.microsoft_windows?
|
376
|
+
|
269
377
|
context "when the service control manager cannot be opened" do
|
270
378
|
let(:scm) { FFI::Pointer::NULL_HANDLE }
|
271
379
|
it "raises a puppet error" do
|
272
|
-
expect{ subject.
|
380
|
+
expect{ subject.start(mock_service_name) }.to raise_error(Puppet::Error)
|
273
381
|
end
|
274
382
|
end
|
275
383
|
|
276
384
|
context "when the service cannot be opened" do
|
277
385
|
let(:service) { FFI::Pointer::NULL_HANDLE }
|
278
386
|
it "raises a puppet error" do
|
279
|
-
expect{ subject.
|
387
|
+
expect{ subject.start(mock_service_name) }.to raise_error(Puppet::Error)
|
280
388
|
end
|
281
389
|
end
|
282
390
|
|
283
|
-
context "when the service can be opened
|
284
|
-
|
285
|
-
|
286
|
-
|
391
|
+
context "when the service can be opened" do
|
392
|
+
service = Puppet::Util::Windows::Service
|
393
|
+
valid_initial_states = service::SERVICE_STATES.keys - [service::SERVICE_STOPPED]
|
394
|
+
final_state = service::SERVICE_STOPPED
|
395
|
+
|
396
|
+
include_examples "a service action that transitions the service state", :stop, valid_initial_states, service::SERVICE_STOP_PENDING, final_state do
|
397
|
+
let(:initial_state) { subject::SERVICE_RUNNING }
|
398
|
+
let(:mock_state_transition) do
|
399
|
+
lambda do
|
400
|
+
subject.stubs(:ControlService).returns(1)
|
401
|
+
end
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
it "raises a Puppet::Error if ControlService returns false" do
|
406
|
+
expect_successful_status_query_and_return(dwCurrentState: subject::SERVICE_RUNNING)
|
407
|
+
|
408
|
+
subject.stubs(:ControlService).returns(FFI::WIN32_FALSE)
|
409
|
+
|
410
|
+
expect { subject.stop(mock_service_name) }.to raise_error(Puppet::Error)
|
287
411
|
end
|
288
|
-
|
289
|
-
|
290
|
-
|
412
|
+
|
413
|
+
it "stops the service" do
|
414
|
+
expect_successful_status_queries_and_return(
|
415
|
+
{ dwCurrentState: subject::SERVICE_RUNNING },
|
416
|
+
{ dwCurrentState: subject::SERVICE_STOPPED }
|
417
|
+
)
|
418
|
+
|
419
|
+
subject.expects(:ControlService).returns(1)
|
420
|
+
|
421
|
+
subject.stop(mock_service_name)
|
291
422
|
end
|
292
423
|
end
|
424
|
+
end
|
293
425
|
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
context "when the service
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOPPED})
|
302
|
-
subject.stop(mock_service_name)
|
426
|
+
describe "#resume" do
|
427
|
+
next unless Puppet.features.microsoft_windows?
|
428
|
+
|
429
|
+
context "when the service control manager cannot be opened" do
|
430
|
+
let(:scm) { FFI::Pointer::NULL_HANDLE }
|
431
|
+
it "raises a puppet error" do
|
432
|
+
expect{ subject.start(mock_service_name) }.to raise_error(Puppet::Error)
|
303
433
|
end
|
304
434
|
end
|
305
435
|
|
306
|
-
context "when the service
|
307
|
-
|
308
|
-
|
309
|
-
|
436
|
+
context "when the service cannot be opened" do
|
437
|
+
let(:service) { FFI::Pointer::NULL_HANDLE }
|
438
|
+
it "raises a puppet error" do
|
439
|
+
expect{ subject.start(mock_service_name) }.to raise_error(Puppet::Error)
|
310
440
|
end
|
441
|
+
end
|
311
442
|
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
443
|
+
context "when the service can be opened" do
|
444
|
+
service = Puppet::Util::Windows::Service
|
445
|
+
valid_initial_states = [
|
446
|
+
service::SERVICE_PAUSE_PENDING,
|
447
|
+
service::SERVICE_PAUSED,
|
448
|
+
service::SERVICE_CONTINUE_PENDING
|
449
|
+
]
|
450
|
+
final_state = service::SERVICE_RUNNING
|
451
|
+
|
452
|
+
include_examples "a service action that transitions the service state", :resume, valid_initial_states, service::SERVICE_CONTINUE_PENDING, final_state do
|
453
|
+
let(:initial_state) { service::SERVICE_PAUSED }
|
454
|
+
let(:mock_state_transition) do
|
455
|
+
lambda do
|
456
|
+
# We need to mock the status query because in the block for #resume, we
|
457
|
+
# wait for the service to enter the SERVICE_PAUSED state prior to
|
458
|
+
# performing the transition (in case it is in SERVICE_PAUSE_PENDING).
|
459
|
+
expect_successful_status_query_and_return(dwCurrentState: subject::SERVICE_PAUSED)
|
460
|
+
|
461
|
+
subject.stubs(:ControlService).returns(1)
|
462
|
+
end
|
463
|
+
end
|
320
464
|
end
|
321
465
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
466
|
+
context "waiting for the SERVICE_PAUSE_PENDING => SERVICE_PAUSED transition to finish before resuming it" do
|
467
|
+
before(:each) do
|
468
|
+
# This mocks the status query to return the SERVICE_RUNNING state by default.
|
469
|
+
# Otherwise, we will fail the tests in the latter parts of the code where we
|
470
|
+
# wait for the service to finish transitioning to the 'SERVICE_RUNNING' state.
|
471
|
+
subject::SERVICE_STATUS_PROCESS.stubs(:new).returns(dwCurrentState: subject::SERVICE_RUNNING)
|
472
|
+
|
473
|
+
expect_successful_status_query_and_return(dwCurrentState: subject::SERVICE_PAUSE_PENDING)
|
474
|
+
|
475
|
+
subject.stubs(:ControlService).returns(1)
|
476
|
+
end
|
477
|
+
|
478
|
+
include_examples "a service action waiting on a pending transition", service::SERVICE_PAUSE_PENDING do
|
479
|
+
let(:action) { :resume }
|
480
|
+
end
|
327
481
|
end
|
328
|
-
end
|
329
482
|
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_RUNNING, :dwWaitHint => 0, :dwCheckPoint => 0}).times(10)
|
338
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOP_PENDING, :dwWaitHint => 30000, :dwCheckPoint => 1})
|
339
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOP_PENDING, :dwWaitHint => 30000, :dwCheckPoint => 50})
|
340
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOPPED})
|
341
|
-
subject.stop(mock_service_name)
|
483
|
+
it "raises a Puppet::Error if ControlService returns false" do
|
484
|
+
expect_successful_status_query_and_return(dwCurrentState: subject::SERVICE_PAUSED)
|
485
|
+
expect_successful_status_query_and_return(dwCurrentState: subject::SERVICE_PAUSED)
|
486
|
+
|
487
|
+
subject.stubs(:ControlService).returns(FFI::WIN32_FALSE)
|
488
|
+
|
489
|
+
expect { subject.resume(mock_service_name) }.to raise_error(Puppet::Error)
|
342
490
|
end
|
491
|
+
|
492
|
+
it "resumes the service" do
|
493
|
+
expect_successful_status_queries_and_return(
|
494
|
+
{ dwCurrentState: subject::SERVICE_PAUSED },
|
495
|
+
{ dwCurrentState: subject::SERVICE_PAUSED },
|
496
|
+
{ dwCurrentState: subject::SERVICE_RUNNING }
|
497
|
+
)
|
498
|
+
|
499
|
+
subject.expects(:ControlService).returns(1)
|
343
500
|
|
344
|
-
|
345
|
-
# the first call is to wait_for_state, which we don't test here
|
346
|
-
expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_RUNNING, :dwWaitHint => 0, :dwCheckPoint => 0}).times(31)
|
347
|
-
subject.expects(:sleep).times(30).with(1)
|
348
|
-
expect{subject.stop(mock_service_name)}.to raise_error(Puppet::Error)
|
501
|
+
subject.resume(mock_service_name)
|
349
502
|
end
|
350
503
|
end
|
351
504
|
end
|