puppet 6.0.0 → 6.1.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 (259) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/Gemfile.lock +20 -20
  4. data/Guardfile.example +76 -0
  5. data/LICENSE +189 -4
  6. data/README.md +3 -3
  7. data/Rakefile +5 -2
  8. data/ext/solaris/smf/svc-puppetd +8 -1
  9. data/ext/solaris/smf/svc-puppetmasterd +8 -1
  10. data/lib/puppet/application/apply.rb +100 -59
  11. data/lib/puppet/application/cert.rb +4 -114
  12. data/lib/puppet/application/device.rb +48 -32
  13. data/lib/puppet/application/script.rb +1 -1
  14. data/lib/puppet/application/ssl.rb +135 -51
  15. data/lib/puppet/application.rb +5 -0
  16. data/lib/puppet/configurer.rb +2 -3
  17. data/lib/puppet/defaults.rb +33 -49
  18. data/lib/puppet/etc.rb +20 -0
  19. data/lib/puppet/face/config.rb +3 -3
  20. data/lib/puppet/face/key.rb +1 -1
  21. data/lib/puppet/face/node/clean.rb +0 -1
  22. data/lib/puppet/feature/base.rb +1 -1
  23. data/lib/puppet/file_bucket/dipper.rb +1 -1
  24. data/lib/puppet/file_serving/fileset.rb +1 -1
  25. data/lib/puppet/functions/abs.rb +1 -1
  26. data/lib/puppet/functions/new.rb +1 -1
  27. data/lib/puppet/module/task.rb +29 -38
  28. data/lib/puppet/pal/catalog_compiler.rb +96 -0
  29. data/lib/puppet/pal/compiler.rb +221 -0
  30. data/lib/puppet/pal/function_signature.rb +52 -0
  31. data/lib/puppet/pal/json_catalog_encoder.rb +67 -0
  32. data/lib/puppet/pal/pal_api.rb +15 -0
  33. data/lib/puppet/pal/pal_impl.rb +523 -0
  34. data/lib/puppet/pal/plan_signature.rb +71 -0
  35. data/lib/puppet/pal/script_compiler.rb +71 -0
  36. data/lib/puppet/pal/task_signature.rb +58 -0
  37. data/lib/puppet/parser/catalog_compiler.rb +24 -0
  38. data/lib/puppet/parser/compiler.rb +3 -1
  39. data/lib/puppet/parser/functions/generate.rb +7 -6
  40. data/lib/puppet/plugins/configuration.rb +5 -1
  41. data/lib/puppet/pops/evaluator/collectors/abstract_collector.rb +3 -1
  42. data/lib/puppet/pops/evaluator/deferred_resolver.rb +3 -0
  43. data/lib/puppet/pops/evaluator/evaluator_impl.rb +5 -1
  44. data/lib/puppet/pops/evaluator/external_syntax_support.rb +3 -3
  45. data/lib/puppet/pops/evaluator/runtime3_converter.rb +2 -2
  46. data/lib/puppet/pops/loader/ruby_legacy_function_instantiator.rb +19 -10
  47. data/lib/puppet/pops/loader/task_instantiator.rb +13 -70
  48. data/lib/puppet/pops/parser/heredoc_support.rb +1 -2
  49. data/lib/puppet/pops/parser/lexer2.rb +1 -1
  50. data/lib/puppet/pops/pcore.rb +10 -33
  51. data/lib/puppet/pops/serialization/to_data_converter.rb +9 -1
  52. data/lib/puppet/pops/serialization.rb +1 -0
  53. data/lib/puppet/pops/types/p_timespan_type.rb +2 -2
  54. data/lib/puppet/pops/types/string_converter.rb +18 -4
  55. data/lib/puppet/pops/validation/checker4_0.rb +17 -2
  56. data/lib/puppet/provider/exec.rb +59 -57
  57. data/lib/puppet/provider/group/aix.rb +18 -2
  58. data/lib/puppet/provider/group/windows_adsi.rb +7 -3
  59. data/lib/puppet/provider/nameservice.rb +1 -25
  60. data/lib/puppet/provider/package/dnf.rb +2 -0
  61. data/lib/puppet/provider/package/pkgng.rb +37 -21
  62. data/lib/puppet/provider/package/portage.rb +2 -2
  63. data/lib/puppet/provider/package/windows/exe_package.rb +16 -10
  64. data/lib/puppet/provider/package/windows/msi_package.rb +8 -0
  65. data/lib/puppet/provider/package/windows/package.rb +9 -1
  66. data/lib/puppet/provider/package/windows.rb +2 -2
  67. data/lib/puppet/provider/package/yum.rb +1 -1
  68. data/lib/puppet/provider/parsedfile.rb +25 -4
  69. data/lib/puppet/provider/service/launchd.rb +19 -3
  70. data/lib/puppet/provider/service/smf.rb +54 -0
  71. data/lib/puppet/provider/service/systemd.rb +19 -0
  72. data/lib/puppet/provider/service/upstart.rb +1 -0
  73. data/lib/puppet/provider/service/windows.rb +22 -5
  74. data/lib/puppet/provider/user/aix.rb +48 -2
  75. data/lib/puppet/provider/user/useradd.rb +2 -10
  76. data/lib/puppet/provider/user/windows_adsi.rb +9 -1
  77. data/lib/puppet/resource/catalog.rb +1 -5
  78. data/lib/puppet/resource.rb +3 -1
  79. data/lib/puppet/ssl/host.rb +26 -16
  80. data/lib/puppet/syntax_checkers/epp.rb +34 -0
  81. data/lib/puppet/syntax_checkers/pp.rb +34 -0
  82. data/lib/puppet/transaction/event_manager.rb +13 -1
  83. data/lib/puppet/transaction/persistence.rb +1 -1
  84. data/lib/puppet/transaction/resource_harness.rb +3 -1
  85. data/lib/puppet/type/group.rb +29 -1
  86. data/lib/puppet/type/package.rb +5 -1
  87. data/lib/puppet/type/resources.rb +12 -2
  88. data/lib/puppet/type/schedule.rb +7 -0
  89. data/lib/puppet/type/service.rb +12 -0
  90. data/lib/puppet/type/user.rb +5 -2
  91. data/lib/puppet/type.rb +6 -0
  92. data/lib/puppet/util/command_line.rb +2 -3
  93. data/lib/puppet/util/execution.rb +15 -1
  94. data/lib/puppet/util/filetype.rb +56 -8
  95. data/lib/puppet/util/log/destinations.rb +3 -2
  96. data/lib/puppet/util/logging.rb +3 -2
  97. data/lib/puppet/util/posix.rb +15 -0
  98. data/lib/puppet/util/selinux.rb +1 -1
  99. data/lib/puppet/util/storage.rb +12 -0
  100. data/lib/puppet/util/windows/adsi.rb +79 -2
  101. data/lib/puppet/util/windows/api_types.rb +1 -1
  102. data/lib/puppet/util/windows/process.rb +23 -3
  103. data/lib/puppet/util/windows/registry.rb +29 -5
  104. data/lib/puppet/util/windows/security.rb +14 -0
  105. data/lib/puppet/util/windows/service.rb +294 -74
  106. data/lib/puppet/util/windows/user.rb +3 -5
  107. data/lib/puppet/util.rb +7 -3
  108. data/lib/puppet/version.rb +1 -1
  109. data/lib/puppet.rb +1 -0
  110. data/lib/puppet_pal.rb +5 -1099
  111. data/locales/ja/puppet.po +952 -986
  112. data/locales/puppet.pot +592 -347
  113. data/man/man5/puppet.conf.5 +26 -31
  114. data/man/man8/puppet-agent.8 +1 -1
  115. data/man/man8/puppet-apply.8 +1 -1
  116. data/man/man8/puppet-catalog.8 +1 -1
  117. data/man/man8/puppet-config.8 +4 -4
  118. data/man/man8/puppet-describe.8 +1 -1
  119. data/man/man8/puppet-device.8 +23 -19
  120. data/man/man8/puppet-doc.8 +1 -1
  121. data/man/man8/puppet-epp.8 +1 -1
  122. data/man/man8/puppet-facts.8 +1 -1
  123. data/man/man8/puppet-filebucket.8 +1 -1
  124. data/man/man8/puppet-generate.8 +1 -1
  125. data/man/man8/puppet-help.8 +1 -1
  126. data/man/man8/puppet-key.8 +2 -2
  127. data/man/man8/puppet-lookup.8 +1 -1
  128. data/man/man8/puppet-man.8 +1 -1
  129. data/man/man8/puppet-module.8 +1 -1
  130. data/man/man8/puppet-node.8 +1 -1
  131. data/man/man8/puppet-parser.8 +1 -1
  132. data/man/man8/puppet-plugin.8 +1 -1
  133. data/man/man8/puppet-report.8 +1 -1
  134. data/man/man8/puppet-resource.8 +1 -1
  135. data/man/man8/puppet-script.8 +1 -1
  136. data/man/man8/puppet-ssl.8 +26 -3
  137. data/man/man8/puppet-status.8 +1 -1
  138. data/man/man8/puppet.8 +2 -2
  139. data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/bad_func_load.rb +11 -0
  140. data/spec/fixtures/unit/provider/package/pkgng/pkg.query +7 -1
  141. data/spec/fixtures/unit/provider/package/pkgng/pkg.query.zsh +1 -0
  142. data/spec/fixtures/unit/provider/service/smf/svcs_fmri.out +6 -0
  143. data/spec/fixtures/unit/provider/service/smf/svcs_multiple_fmris.out +13 -0
  144. data/spec/integration/application/apply_spec.rb +4 -1
  145. data/spec/integration/parser/collection_spec.rb +4 -8
  146. data/spec/integration/provider/service/windows_spec.rb +5 -5
  147. data/spec/integration/ssl/key_spec.rb +0 -4
  148. data/spec/integration/transaction_spec.rb +559 -0
  149. data/spec/integration/type/file_spec.rb +6 -6
  150. data/spec/integration/util/windows/registry_spec.rb +39 -0
  151. data/spec/integration/util/windows/security_spec.rb +10 -7
  152. data/spec/integration/util/windows/user_spec.rb +37 -17
  153. data/spec/lib/puppet/test_ca.rb +1 -1
  154. data/spec/spec_helper.rb +1 -1
  155. data/spec/unit/agent_spec.rb +2 -2
  156. data/spec/unit/application/apply_spec.rb +55 -2
  157. data/spec/unit/application/device_spec.rb +10 -7
  158. data/spec/unit/application/face_base_spec.rb +1 -1
  159. data/spec/unit/application/lookup_spec.rb +2 -1
  160. data/spec/unit/application/ssl_spec.rb +178 -109
  161. data/spec/unit/application_spec.rb +29 -11
  162. data/spec/unit/configurer/downloader_spec.rb +1 -1
  163. data/spec/unit/configurer_spec.rb +16 -5
  164. data/spec/unit/etc_spec.rb +25 -0
  165. data/spec/unit/face/node_spec.rb +1 -3
  166. data/spec/unit/face/parser_spec.rb +15 -0
  167. data/spec/unit/file_serving/fileset_spec.rb +11 -11
  168. data/spec/unit/functions/logging_spec.rb +10 -3
  169. data/spec/unit/indirector/catalog/json_spec.rb +9 -3
  170. data/spec/unit/indirector/yaml_spec.rb +1 -1
  171. data/spec/unit/network/http/connection_spec.rb +2 -2
  172. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +36 -0
  173. data/spec/unit/pops/evaluator/runtime3_converter_spec.rb +22 -4
  174. data/spec/unit/pops/loaders/loader_spec.rb +9 -17
  175. data/spec/unit/pops/loaders/loaders_spec.rb +48 -0
  176. data/spec/unit/pops/loaders/module_loaders_spec.rb +7 -7
  177. data/spec/unit/pops/parser/parse_heredoc_spec.rb +16 -0
  178. data/spec/unit/pops/serialization/to_from_hr_spec.rb +9 -0
  179. data/spec/unit/pops/types/p_timespan_type_spec.rb +22 -0
  180. data/spec/unit/pops/types/p_timestamp_type_spec.rb +19 -0
  181. data/spec/unit/pops/types/string_converter_spec.rb +25 -1
  182. data/spec/unit/pops/types/task_spec.rb +42 -116
  183. data/spec/unit/pops/validator/validator_spec.rb +24 -10
  184. data/spec/unit/provider/exec/posix_spec.rb +24 -0
  185. data/spec/unit/provider/group/aix_spec.rb +20 -6
  186. data/spec/unit/provider/group/ldap_spec.rb +22 -25
  187. data/spec/unit/provider/group/pw_spec.rb +7 -10
  188. data/spec/unit/provider/group/windows_adsi_spec.rb +42 -33
  189. data/spec/unit/provider/nameservice/directoryservice_spec.rb +97 -103
  190. data/spec/unit/provider/package/aix_spec.rb +5 -8
  191. data/spec/unit/provider/package/apt_spec.rb +3 -6
  192. data/spec/unit/provider/package/dnf_spec.rb +38 -25
  193. data/spec/unit/provider/package/dpkg_spec.rb +18 -21
  194. data/spec/unit/provider/package/freebsd_spec.rb +4 -7
  195. data/spec/unit/provider/package/gem_spec.rb +41 -41
  196. data/spec/unit/provider/package/hpux_spec.rb +7 -10
  197. data/spec/unit/provider/package/macports_spec.rb +13 -15
  198. data/spec/unit/provider/package/nim_spec.rb +3 -10
  199. data/spec/unit/provider/package/openbsd_spec.rb +14 -17
  200. data/spec/unit/provider/package/pip3_spec.rb +3 -6
  201. data/spec/unit/provider/package/pip_spec.rb +45 -49
  202. data/spec/unit/provider/package/pkgin_spec.rb +13 -18
  203. data/spec/unit/provider/package/pkgng_spec.rb +32 -27
  204. data/spec/unit/provider/package/puppet_gem_spec.rb +6 -9
  205. data/spec/unit/provider/package/tdnf_spec.rb +9 -12
  206. data/spec/unit/provider/package/windows/exe_package_spec.rb +3 -3
  207. data/spec/unit/provider/package/windows_spec.rb +4 -4
  208. data/spec/unit/provider/package/yum_spec.rb +30 -16
  209. data/spec/unit/provider/package/zypper_spec.rb +17 -19
  210. data/spec/unit/provider/service/bsd_spec.rb +7 -9
  211. data/spec/unit/provider/service/daemontools_spec.rb +12 -16
  212. data/spec/unit/provider/service/debian_spec.rb +6 -10
  213. data/spec/unit/provider/service/freebsd_spec.rb +2 -2
  214. data/spec/unit/provider/service/launchd_spec.rb +19 -0
  215. data/spec/unit/provider/service/openbsd_spec.rb +13 -17
  216. data/spec/unit/provider/service/rcng_spec.rb +2 -4
  217. data/spec/unit/provider/service/redhat_spec.rb +12 -11
  218. data/spec/unit/provider/service/runit_spec.rb +7 -14
  219. data/spec/unit/provider/service/smf_spec.rb +77 -13
  220. data/spec/unit/provider/service/src_spec.rb +11 -16
  221. data/spec/unit/provider/service/systemd_spec.rb +39 -1
  222. data/spec/unit/provider/service/windows_spec.rb +39 -7
  223. data/spec/unit/provider/user/aix_spec.rb +43 -2
  224. data/spec/unit/provider/user/hpux_spec.rb +3 -5
  225. data/spec/unit/provider/user/ldap_spec.rb +29 -32
  226. data/spec/unit/provider/user/pw_spec.rb +10 -13
  227. data/spec/unit/provider/user/useradd_spec.rb +2 -2
  228. data/spec/unit/provider/user/windows_adsi_spec.rb +4 -4
  229. data/spec/unit/puppet_pal_2pec.rb +6 -6
  230. data/spec/unit/puppet_pal_catalog_spec.rb +58 -0
  231. data/spec/unit/resource/catalog_spec.rb +2 -2
  232. data/spec/unit/resource_spec.rb +31 -0
  233. data/spec/unit/ssl/host_spec.rb +22 -1
  234. data/spec/unit/ssl/key_spec.rb +2 -4
  235. data/spec/unit/task_spec.rb +50 -5
  236. data/spec/unit/transaction/event_manager_spec.rb +12 -1
  237. data/spec/unit/transaction/persistence_spec.rb +4 -4
  238. data/spec/unit/transaction/resource_harness_spec.rb +18 -0
  239. data/spec/unit/type/group_spec.rb +11 -3
  240. data/spec/unit/type/resources_spec.rb +18 -0
  241. data/spec/unit/type/service_spec.rb +27 -1
  242. data/spec/unit/util/execution_spec.rb +77 -0
  243. data/spec/unit/util/filetype_spec.rb +13 -5
  244. data/spec/unit/util/log/destinations_spec.rb +10 -0
  245. data/spec/unit/util/logging_spec.rb +58 -41
  246. data/spec/unit/util/monkey_patches_spec.rb +18 -5
  247. data/spec/unit/util/posix_spec.rb +28 -0
  248. data/spec/unit/util/selinux_spec.rb +4 -0
  249. data/spec/unit/util/storage_spec.rb +107 -0
  250. data/spec/unit/util/suidmanager_spec.rb +1 -3
  251. data/spec/unit/util/windows/adsi_spec.rb +95 -0
  252. data/spec/unit/util/windows/service_spec.rb +377 -131
  253. metadata +24 -11
  254. data/ext/autotest/Rakefile +0 -8
  255. data/ext/autotest/config +0 -43
  256. data/ext/autotest/readme.rst +0 -16
  257. data/spec/fixtures/unit/provider/package/pkgng/pkg.info +0 -7
  258. data/spec/fixtures/unit/provider/package/pkgng/pkg.query_absent +0 -1
  259. data/spec/watchr.rb +0 -137
@@ -4,6 +4,16 @@ require 'spec_helper'
4
4
  describe "Puppet::Util::Windows::Service", :if => Puppet.features.microsoft_windows? do
5
5
  require 'puppet/util/windows'
6
6
 
7
+ before(:each) do
8
+ Puppet::Util::Windows::Error.stubs(:format_error_code)
9
+ .with(anything)
10
+ .returns("fake error!")
11
+ end
12
+
13
+ def service_state_str(state)
14
+ Puppet::Util::Windows::Service::SERVICE_STATES[state].to_s
15
+ end
16
+
7
17
  # The following should emulate a successful call to the private function
8
18
  # query_status that returns the value of query_return. This should give
9
19
  # us a way to mock changes in service status.
@@ -15,6 +25,12 @@ describe "Puppet::Util::Windows::Service", :if => Puppet.features.microsoft_wind
15
25
  subject::SERVICE_STATUS_PROCESS.expects(:new).in_sequence(status_checks).returns(query_return)
16
26
  end
17
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
+
18
34
  # The following should emulate a successful call to the private function
19
35
  # query_config that returns the value of query_return. This should give
20
36
  # us a way to mock changes in service configuration.
@@ -32,12 +48,11 @@ describe "Puppet::Util::Windows::Service", :if => Puppet.features.microsoft_wind
32
48
  let(:mock_service_name) { mock() }
33
49
  let(:service) { mock() }
34
50
  let(:scm) { mock() }
51
+ let(:timeout) { 30 }
35
52
 
36
53
  before do
37
54
  subject.stubs(:QueryServiceStatusEx).returns(1)
38
55
  subject.stubs(:QueryServiceConfigW).returns(1)
39
- subject.stubs(:StartServiceW).returns(1)
40
- subject.stubs(:ControlService).returns(1)
41
56
  subject.stubs(:ChangeServiceConfigW).returns(1)
42
57
  subject.stubs(:OpenSCManagerW).returns(scm)
43
58
  subject.stubs(:OpenServiceW).returns(service)
@@ -47,213 +62,444 @@ describe "Puppet::Util::Windows::Service", :if => Puppet.features.microsoft_wind
47
62
  subject::SERVICE_STATUS_PROCESS.stubs(:new)
48
63
  subject::QUERY_SERVICE_CONFIGW.stubs(:new)
49
64
  subject::SERVICE_STATUS.stubs(:new).returns({:dwCurrentState => subject::SERVICE_RUNNING})
50
- Puppet::Util::Windows::Error.stubs(:new).raises(Puppet::Error.new('fake error'))
65
+ FFI.stubs(:errno).returns(0)
51
66
  FFI::MemoryPointer.stubs(:new).yields(pointer)
52
67
  pointer.stubs(:read_dword)
53
68
  pointer.stubs(:write_dword)
54
69
  pointer.stubs(:size)
70
+ subject.stubs(:sleep)
55
71
  end
56
72
 
57
- describe "#start" do
58
-
73
+ describe "#exists?" do
59
74
  context "when the service control manager cannot be opened" do
60
75
  let(:scm) { FFI::Pointer::NULL_HANDLE }
61
76
  it "raises a puppet error" do
62
- expect{ subject.start(mock_service_name) }.to raise_error(Puppet::Error)
77
+ expect{ subject.exists?(mock_service_name) }.to raise_error(Puppet::Error)
63
78
  end
64
79
  end
65
80
 
66
81
  context "when the service cannot be opened" do
67
82
  let(:service) { FFI::Pointer::NULL_HANDLE }
68
- it "raises a puppet error" do
69
- expect{ subject.start(mock_service_name) }.to raise_error(Puppet::Error)
83
+
84
+ it "returns false if it fails to open because the service does not exist" do
85
+ FFI.stubs(:errno).returns(Puppet::Util::Windows::Service::ERROR_SERVICE_DOES_NOT_EXIST)
86
+
87
+ expect(subject.exists?(mock_service_name)).to be false
70
88
  end
71
- end
72
89
 
73
- context "when the service can be opened and is in the stopped state" do
74
- before do
75
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOPPED})
90
+ it "raises a puppet error if it fails to open for some other reason" do
91
+ expect{ subject.exists?(mock_service_name) }.to raise_error(Puppet::Error)
76
92
  end
93
+ end
77
94
 
78
- it "Starts the service once the service reports SERVICE_RUNNING" do
79
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_RUNNING})
80
- subject.start(mock_service_name)
95
+ context "when the service can be opened" do
96
+ it "returns true" do
97
+ expect(subject.exists?(mock_service_name)).to be true
81
98
  end
99
+ end
100
+ end
101
+
102
+ # This shared example contains the unit tests for the wait_on_pending_state
103
+ # helper as used by service actions like #start and #stop. Before including
104
+ # this shared example, be sure to mock out any intermediate calls prior to
105
+ # the pending transition, and make sure that the post-condition _after_ those
106
+ # intermediate calls leaves the service in the pending state. Before including
107
+ # this example in your tests, be sure to define the following variables in a `let`
108
+ # context:
109
+ # * action -- The service action
110
+ shared_examples "a service action waiting on a pending transition" do |pending_state|
111
+ pending_state_str = Puppet::Util::Windows::Service::SERVICE_STATES[pending_state].to_s
112
+
113
+ final_state = Puppet::Util::Windows::Service::FINAL_STATES[pending_state]
114
+ final_state_str = Puppet::Util::Windows::Service::SERVICE_STATES[final_state].to_s
115
+
116
+ it "raises a Puppet::Error if the service query fails" do
117
+ subject.expects(:QueryServiceStatusEx).in_sequence(status_checks).returns(FFI::WIN32_FALSE)
118
+
119
+ expect { subject.send(action, mock_service_name, timeout: timeout) }.to raise_error(Puppet::Error)
120
+ end
121
+
122
+ it "raises a Puppet::Error if the service unexpectedly transitions to a state other than #{pending_state_str} or #{final_state_str}" do
123
+ invalid_state = (subject::SERVICE_STATES.keys - [pending_state, final_state]).first
124
+
125
+ expect_successful_status_query_and_return(dwCurrentState: invalid_state)
126
+
127
+ expect { subject.send(action, mock_service_name, timeout: timeout) }.to raise_error(Puppet::Error)
128
+ end
129
+
130
+ it "waits for at least 1 second if the wait_hint/10 is < 1 second" do
131
+ expect_successful_status_queries_and_return(
132
+ { :dwCurrentState => pending_state, :dwWaitHint => 0, :dwCheckPoint => 1 },
133
+ { :dwCurrentState => final_state }
134
+ )
135
+
136
+ subject.expects(:sleep).with(1)
137
+
138
+ subject.send(action, mock_service_name, timeout: timeout)
139
+ end
140
+
141
+ it "waits for at most 10 seconds if wait_hint/10 is > 10 seconds" do
142
+ expect_successful_status_queries_and_return(
143
+ { :dwCurrentState => pending_state, :dwWaitHint => 1000000, :dwCheckPoint => 1 },
144
+ { :dwCurrentState => final_state }
145
+ )
82
146
 
83
- it "Raises an error if after calling StartServiceW the service is not in RUNNING or START_PENDING" do
84
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_PAUSED})
85
- expect{ subject.start(mock_service_name) }.to raise_error(Puppet::Error)
147
+ subject.expects(:sleep).with(10)
148
+
149
+ subject.send(action, mock_service_name, timeout: timeout)
150
+ end
151
+
152
+ it "does not raise an error if the service makes any progress while transitioning to #{final_state_str}" do
153
+ expect_successful_status_queries_and_return(
154
+ # The three "pending_state" statuses simulate the scenario where the service
155
+ # makes some progress during the transition right when Puppet's about to
156
+ # time out.
157
+ { :dwCurrentState => pending_state, :dwWaitHint => 100000, :dwCheckPoint => 1 },
158
+ { :dwCurrentState => pending_state, :dwWaitHint => 100000, :dwCheckPoint => 1 },
159
+ { :dwCurrentState => pending_state, :dwWaitHint => 100000, :dwCheckPoint => 2 },
160
+
161
+ { :dwCurrentState => final_state }
162
+ )
163
+
164
+ expect { subject.send(action, mock_service_name, timeout: timeout) }.to_not raise_error
165
+ end
166
+
167
+ it "raises a Puppet::Error if it times out while waiting for the transition to #{final_state_str}" do
168
+ 31.times do
169
+ expect_successful_status_query_and_return(
170
+ dwCurrentState: pending_state,
171
+ dwWaitHint: 10000,
172
+ dwCheckPoint: 1
173
+ )
86
174
  end
87
175
 
88
- it "raises a puppet error if StartServiceW returns false" do
89
- subject.expects(:StartServiceW).returns(FFI::WIN32_FALSE)
90
- expect{ subject.start(mock_service_name) }.to raise_error(Puppet::Error)
176
+ expect { subject.send(action, mock_service_name, timeout: timeout) }.to raise_error(Puppet::Error)
177
+ end
178
+ end
179
+
180
+ # This shared example contains the unit tests for the transition_service_state
181
+ # helper, which is the helper that all of our service actions like #start, #stop
182
+ # delegate to. Including these tests under a shared example lets us include them in each of
183
+ # those service action's unit tests. Before including this example in your tests, be
184
+ # sure to define the following variables in a `let` context:
185
+ # * initial_state -- The initial state of the service prior to performing the state
186
+ # transition
187
+ #
188
+ # * mock_state_transition -- A lambda that mocks the state transition. This should mock
189
+ # any code in the block that's passed to the
190
+ # transition_service_state helper
191
+ #
192
+ # See the unit tests for the #start method to see how this shared example's
193
+ # included.
194
+ #
195
+ shared_examples "a service action that transitions the service state" do |action, valid_initial_states, pending_state, final_state|
196
+ valid_initial_states_str = valid_initial_states.map do |state|
197
+ Puppet::Util::Windows::Service::SERVICE_STATES[state]
198
+ end.join(', ')
199
+ pending_state_str = Puppet::Util::Windows::Service::SERVICE_STATES[pending_state].to_s
200
+ final_state_str = Puppet::Util::Windows::Service::SERVICE_STATES[final_state].to_s
201
+
202
+ it "noops if the service is already in the #{final_state} state" do
203
+ expect_successful_status_query_and_return(dwCurrentState: final_state)
204
+
205
+ expect { subject.send(action, mock_service_name, timeout: timeout) }.to_not raise_error
206
+ end
207
+
208
+ # invalid_initial_states will be empty for the #stop action
209
+ invalid_initial_states = Puppet::Util::Windows::Service::SERVICE_STATES.keys - valid_initial_states - [final_state]
210
+ unless invalid_initial_states.empty?
211
+ it "raises a Puppet::Error if the service's initial state is not one of #{valid_initial_states_str}" do
212
+ invalid_initial_state = invalid_initial_states.first
213
+ expect_successful_status_query_and_return(dwCurrentState: invalid_initial_state)
214
+
215
+ expect{ subject.send(action, mock_service_name, timeout: timeout) }.to raise_error(Puppet::Error)
91
216
  end
92
217
  end
93
218
 
94
- context "when the service hasn't stopped yet:" do
95
- it "waits, then queries again until SERVICE_STOPPED" do
96
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOP_PENDING, :dwWaitHint => 30000, :dwCheckPoint => 1})
97
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOP_PENDING, :dwWaitHint => 30000, :dwCheckPoint => 50})
98
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOPPED})
99
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_RUNNING})
100
- subject.expects(:sleep).with(3).twice
101
- subject.start(mock_service_name)
219
+ context "when there's a pending transition to the #{final_state} state" do
220
+ before(:each) do
221
+ expect_successful_status_query_and_return(dwCurrentState: pending_state)
102
222
  end
103
223
 
104
- it "waits for at least 1 second if wait hint/10 is < 1 second" do
105
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOP_PENDING, :dwWaitHint => 0, :dwCheckPoint => 1})
106
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOPPED})
107
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_RUNNING})
108
- subject.expects(:sleep).with(1)
109
- subject.start(mock_service_name)
224
+ include_examples "a service action waiting on a pending transition", pending_state do
225
+ let(:action) { action }
110
226
  end
227
+ end
228
+
229
+ # If the service action accepts an unsafe pending state as one of the service's
230
+ # initial states, then we need to test that the action waits for the service to
231
+ # transition from that unsafe pending state before doing anything else.
232
+ unsafe_pending_states = valid_initial_states & Puppet::Util::Windows::Service::UNSAFE_PENDING_STATES
233
+ unless unsafe_pending_states.empty?
234
+ unsafe_pending_state = unsafe_pending_states.first
235
+ unsafe_pending_state_str = Puppet::Util::Windows::Service::SERVICE_STATES[unsafe_pending_state]
236
+
237
+ context "waiting for a service with #{unsafe_pending_state_str} as its initial state" do
238
+ before(:each) do
239
+ # This mocks the status query to return the 'final_state' by default. Otherwise,
240
+ # we will fail the tests in the latter parts of the code where we wait for the
241
+ # service to finish transitioning to the 'final_state'.
242
+ subject::SERVICE_STATUS_PROCESS.stubs(:new).returns(dwCurrentState: final_state)
243
+
244
+ # Set our service's initial state
245
+ expect_successful_status_query_and_return(dwCurrentState: unsafe_pending_state)
246
+
247
+ mock_state_transition.call
248
+ end
111
249
 
112
- it "waits for at most 10 seconds if wait hint/10 is > 10 seconds" do
113
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOP_PENDING, :dwWaitHint => 1000000, :dwCheckPoint => 1})
114
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOPPED})
115
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_RUNNING})
116
- subject.expects(:sleep).with(10)
117
- subject.start(mock_service_name)
250
+ include_examples "a service action waiting on a pending transition", unsafe_pending_state do
251
+ let(:action) { action }
252
+ end
118
253
  end
254
+ end
119
255
 
120
- it "raises a puppet error if the service query fails" do
121
- subject.expects(:QueryServiceStatusEx).in_sequence(status_checks).returns(1)
256
+ # reads e.g. "waiting for the service to transition to the SERVICE_RUNNING state after executing the 'start' action"
257
+ #
258
+ # NOTE: This is really unit testing the wait_on_state_transition helper
259
+ context "waiting for the service to transition to the #{final_state_str} state after executing the '#{action}' action" do
260
+ before(:each) do
261
+ # Set our service's initial state prior to performing the state transition
262
+ expect_successful_status_query_and_return(dwCurrentState: initial_state)
263
+
264
+ mock_state_transition.call
265
+ end
266
+
267
+ it "raises a Puppet::Error if the service query fails" do
122
268
  subject.expects(:QueryServiceStatusEx).in_sequence(status_checks).returns(FFI::WIN32_FALSE)
123
- expect{subject.start(mock_service_name)}.to raise_error(Puppet::Error)
269
+
270
+ expect { subject.send(action, mock_service_name, timeout: timeout) }.to raise_error(Puppet::Error)
124
271
  end
125
272
 
126
- it "raises a puppet error if the services configured dwWaitHint is 0, 30 seconds have passed and dwCheckPoint hasn't increased" do
127
- # the number of times here is a little strange: there are 31 and 32 status queries sleeps because:
128
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOP_PENDING, :dwWaitHint => 0, :dwCheckPoint => 0}).times(31)
129
- subject.expects(:sleep).times(30).with(1)
130
- expect{subject.start(mock_service_name)}.to raise_error(Puppet::Error)
273
+ it "waits, then queries again until it transitions to #{final_state_str}" do
274
+ expect_successful_status_queries_and_return(
275
+ { :dwCurrentState => initial_state },
276
+ { :dwCurrentState => initial_state },
277
+ { :dwCurrentState => final_state }
278
+ )
279
+
280
+ subject.expects(:sleep).with(1).twice
281
+
282
+ subject.send(action, mock_service_name, timeout: timeout)
131
283
  end
132
284
 
133
- it "raises a puppet error if the services configured dwWaitHint has passed and dwCheckPoint hasn't increased" do
134
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOP_PENDING, :dwWaitHint => 40000, :dwCheckPoint => 0}).times(11)
135
- subject.expects(:sleep).times(10).with(4)
136
- expect{subject.start(mock_service_name)}.to raise_error(Puppet::Error)
285
+ context "when it transitions to the #{pending_state_str} state" do
286
+ before(:each) do
287
+ expect_successful_status_query_and_return(dwCurrentState: pending_state)
288
+ end
289
+
290
+ include_examples "a service action waiting on a pending transition", pending_state do
291
+ let(:action) { action }
292
+ end
137
293
  end
138
294
 
139
- it "Does not raise an error if the service makes progress" do
140
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOP_PENDING, :dwWaitHint => 0, :dwCheckPoint => 0})
141
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOP_PENDING, :dwWaitHint => 0, :dwCheckPoint => 2})
142
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOP_PENDING, :dwWaitHint => 0, :dwCheckPoint => 30})
143
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOP_PENDING, :dwWaitHint => 0, :dwCheckPoint => 50})
144
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOP_PENDING, :dwWaitHint => 0, :dwCheckPoint => 98})
145
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOPPED})
146
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_RUNNING})
147
- subject.expects(:sleep).times(5).with(1)
148
- expect{subject.start(mock_service_name)}.to_not raise_error
295
+ it "raises a Puppet::Error if it times out while waiting for the transition to #{final_state_str}" do
296
+ 31.times do
297
+ expect_successful_status_query_and_return(dwCurrentState: initial_state)
298
+ end
299
+
300
+ expect { subject.send(action, mock_service_name, timeout: timeout) }.to raise_error(Puppet::Error)
149
301
  end
150
302
  end
303
+ end
151
304
 
152
- context "when the service ends up in START_PENDING:" do
153
- it "waits, then queries again until SERVICE_RUNNING" do
154
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOPPED})
155
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_START_PENDING, :dwWaitHint => 30000, :dwCheckPoint => 1})
156
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_START_PENDING, :dwWaitHint => 30000, :dwCheckPoint => 50})
157
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_RUNNING})
158
- subject.expects(:sleep).with(3).twice
159
- subject.start(mock_service_name)
305
+ describe "#start" do
306
+ # rspec will still try to load the tests even though
307
+ # the :if => Puppet.features.microsoft_windows? filter
308
+ # is passed-in to the top-level describe block on
309
+ # non-Windows platforms; it just won't run them. However
310
+ # on these platforms, the loading will fail because this
311
+ # test uses a shared example that references variables
312
+ # from the Windows::Service module when building the unit
313
+ # tests, which is only available on Windows platforms.
314
+ # Thus, we add the next here to ensure that rspec does not
315
+ # attempt to load our test code. This is OK for us to do
316
+ # because we do not want to run these tests on non-Windows
317
+ # platforms.
318
+ next unless Puppet.features.microsoft_windows?
319
+
320
+ context "when the service control manager cannot be opened" do
321
+ let(:scm) { FFI::Pointer::NULL_HANDLE }
322
+ it "raises a puppet error" do
323
+ expect{ subject.start(mock_service_name, timeout: timeout) }.to raise_error(Puppet::Error)
160
324
  end
325
+ end
161
326
 
162
- it "waits for at least 1 second if wait hint/10 is < 1 second" do
163
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOPPED})
164
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_START_PENDING, :dwWaitHint => 0, :dwCheckPoint => 1})
165
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_RUNNING})
166
- subject.expects(:sleep).with(1)
167
- subject.start(mock_service_name)
327
+ context "when the service cannot be opened" do
328
+ let(:service) { FFI::Pointer::NULL_HANDLE }
329
+ it "raises a puppet error" do
330
+ expect{ subject.start(mock_service_name, timeout: timeout) }.to raise_error(Puppet::Error)
168
331
  end
332
+ end
169
333
 
170
- it "waits for at most 10 seconds if wait hint/10 is > 10 seconds" do
171
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOPPED})
172
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_START_PENDING, :dwWaitHint => 1000000, :dwCheckPoint => 1})
173
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_RUNNING})
174
- subject.expects(:sleep).with(10)
175
- subject.start(mock_service_name)
334
+ context "when the service can be opened" do
335
+ # Can't use rspec's subject here because that
336
+ # can only be referenced inside an 'it' block.
337
+ service = Puppet::Util::Windows::Service
338
+ valid_initial_states = [
339
+ service::SERVICE_STOP_PENDING,
340
+ service::SERVICE_STOPPED,
341
+ service::SERVICE_START_PENDING
342
+ ]
343
+ final_state = service::SERVICE_RUNNING
344
+
345
+ include_examples "a service action that transitions the service state", :start, valid_initial_states, service::SERVICE_START_PENDING, final_state do
346
+ let(:initial_state) { subject::SERVICE_STOPPED }
347
+ let(:mock_state_transition) do
348
+ lambda do
349
+ subject.stubs(:StartServiceW).returns(1)
350
+ end
351
+ end
176
352
  end
177
353
 
178
- it "raises a puppet error if the service's configured dwWaitHint has passed and dwCheckPoint hasn't increased" do
179
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOPPED})
180
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_START_PENDING, :dwWaitHint => 40000, :dwCheckPoint => 0}).times(11)
181
- subject.expects(:sleep).times(10).with(4)
182
- expect{subject.start(mock_service_name)}.to raise_error(Puppet::Error)
354
+ it "raises a Puppet::Error if StartServiceW returns false" do
355
+ expect_successful_status_query_and_return(dwCurrentState: subject::SERVICE_STOPPED)
356
+
357
+ subject.expects(:StartServiceW).returns(FFI::WIN32_FALSE)
358
+
359
+ expect { subject.start(mock_service_name, timeout: timeout) }.to raise_error(Puppet::Error)
183
360
  end
184
361
 
185
- it "Does not raise an error if the service makes progress" do
186
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOPPED})
187
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_START_PENDING, :dwWaitHint => 0, :dwCheckPoint => 0})
188
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_START_PENDING, :dwWaitHint => 0, :dwCheckPoint => 2})
189
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_START_PENDING, :dwWaitHint => 0, :dwCheckPoint => 30})
190
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_START_PENDING, :dwWaitHint => 0, :dwCheckPoint => 50})
191
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_START_PENDING, :dwWaitHint => 0, :dwCheckPoint => 98})
192
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_RUNNING})
193
- subject.expects(:sleep).times(5).with(1)
194
- expect{subject.start(mock_service_name)}.to_not raise_error
362
+ it "starts the service" do
363
+ expect_successful_status_queries_and_return(
364
+ { dwCurrentState: subject::SERVICE_STOPPED },
365
+ { dwCurrentState: subject::SERVICE_RUNNING }
366
+ )
367
+
368
+ subject.expects(:StartServiceW).returns(1)
369
+
370
+ subject.start(mock_service_name, timeout: timeout)
195
371
  end
196
372
  end
197
373
  end
198
374
 
199
375
  describe "#stop" do
376
+ next unless Puppet.features.microsoft_windows?
377
+
200
378
  context "when the service control manager cannot be opened" do
201
379
  let(:scm) { FFI::Pointer::NULL_HANDLE }
202
380
  it "raises a puppet error" do
203
- expect{ subject.stop(mock_service_name) }.to raise_error(Puppet::Error)
381
+ expect{ subject.start(mock_service_name, timeout: timeout) }.to raise_error(Puppet::Error)
204
382
  end
205
383
  end
206
384
 
207
385
  context "when the service cannot be opened" do
208
386
  let(:service) { FFI::Pointer::NULL_HANDLE }
209
387
  it "raises a puppet error" do
210
- expect{ subject.stop(mock_service_name) }.to raise_error(Puppet::Error)
388
+ expect{ subject.start(mock_service_name, timeout: timeout) }.to raise_error(Puppet::Error)
211
389
  end
212
390
  end
213
391
 
214
- context "when the service can be opened and is in the running state:" do
215
- before do
216
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_RUNNING})
392
+ context "when the service can be opened" do
393
+ service = Puppet::Util::Windows::Service
394
+ valid_initial_states = service::SERVICE_STATES.keys - [service::SERVICE_STOPPED]
395
+ final_state = service::SERVICE_STOPPED
396
+
397
+ include_examples "a service action that transitions the service state", :stop, valid_initial_states, service::SERVICE_STOP_PENDING, final_state do
398
+ let(:initial_state) { subject::SERVICE_RUNNING }
399
+ let(:mock_state_transition) do
400
+ lambda do
401
+ subject.stubs(:ControlService).returns(1)
402
+ end
403
+ end
217
404
  end
218
405
 
219
- it "Sends the SERVICE_CONTROL_STOP to the service once the service reports SERVICE_RUNNING" do
220
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOPPED})
221
- subject.stop(mock_service_name)
406
+ it "raises a Puppet::Error if ControlService returns false" do
407
+ expect_successful_status_query_and_return(dwCurrentState: subject::SERVICE_RUNNING)
408
+
409
+ subject.stubs(:ControlService).returns(FFI::WIN32_FALSE)
410
+
411
+ expect { subject.stop(mock_service_name, timeout: timeout) }.to raise_error(Puppet::Error)
222
412
  end
223
413
 
224
- it "Raises an error if after calling ControlService the service is not in STOPPED or STOP_PENDING" do
225
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_PAUSED})
226
- expect{ subject.stop(mock_service_name) }.to raise_error(Puppet::Error)
414
+ it "stops the service" do
415
+ expect_successful_status_queries_and_return(
416
+ { dwCurrentState: subject::SERVICE_RUNNING },
417
+ { dwCurrentState: subject::SERVICE_STOPPED }
418
+ )
419
+
420
+ subject.expects(:ControlService).returns(1)
421
+
422
+ subject.stop(mock_service_name, timeout: timeout)
227
423
  end
424
+ end
425
+ end
426
+
427
+ describe "#resume" do
428
+ next unless Puppet.features.microsoft_windows?
228
429
 
229
- it "raises a puppet error if ControlService returns false" do
230
- subject.expects(:ControlService).returns(FFI::WIN32_FALSE)
231
- expect{ subject.stop(mock_service_name) }.to raise_error(Puppet::Error)
430
+ context "when the service control manager cannot be opened" do
431
+ let(:scm) { FFI::Pointer::NULL_HANDLE }
432
+ it "raises a puppet error" do
433
+ expect{ subject.start(mock_service_name, timeout: timeout) }.to raise_error(Puppet::Error)
232
434
  end
233
435
  end
234
436
 
235
- # No need to retest much of the wait functionality here, since
236
- # both stop and start use the wait_for_pending_transition helper
237
- # which is tested in the start unit tests.
238
- context "when the service hasn't started yet:" do
239
- it "waits, then queries again until SERVICE_STOPPED" do
240
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_START_PENDING, :dwWaitHint => 30000, :dwCheckPoint => 1})
241
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_START_PENDING, :dwWaitHint => 30000, :dwCheckPoint => 50})
242
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_RUNNING})
243
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOPPED})
244
- subject.expects(:sleep).with(3).twice
245
- subject.stop(mock_service_name)
437
+ context "when the service cannot be opened" do
438
+ let(:service) { FFI::Pointer::NULL_HANDLE }
439
+ it "raises a puppet error" do
440
+ expect{ subject.start(mock_service_name, timeout: timeout) }.to raise_error(Puppet::Error)
246
441
  end
247
442
  end
248
443
 
249
- context "when the service ends up in STOP_PENDING:" do
250
- it "waits, then queries again until SERVICE_RUNNING" do
251
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_RUNNING})
252
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOP_PENDING, :dwWaitHint => 30000, :dwCheckPoint => 1})
253
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOP_PENDING, :dwWaitHint => 30000, :dwCheckPoint => 50})
254
- expect_successful_status_query_and_return({:dwCurrentState => subject::SERVICE_STOPPED})
255
- subject.expects(:sleep).with(3).twice
256
- subject.stop(mock_service_name)
444
+ context "when the service can be opened" do
445
+ service = Puppet::Util::Windows::Service
446
+ valid_initial_states = [
447
+ service::SERVICE_PAUSE_PENDING,
448
+ service::SERVICE_PAUSED,
449
+ service::SERVICE_CONTINUE_PENDING
450
+ ]
451
+ final_state = service::SERVICE_RUNNING
452
+
453
+ include_examples "a service action that transitions the service state", :resume, valid_initial_states, service::SERVICE_CONTINUE_PENDING, final_state do
454
+ let(:initial_state) { service::SERVICE_PAUSED }
455
+ let(:mock_state_transition) do
456
+ lambda do
457
+ # We need to mock the status query because in the block for #resume, we
458
+ # wait for the service to enter the SERVICE_PAUSED state prior to
459
+ # performing the transition (in case it is in SERVICE_PAUSE_PENDING).
460
+ expect_successful_status_query_and_return(dwCurrentState: subject::SERVICE_PAUSED)
461
+
462
+ subject.stubs(:ControlService).returns(1)
463
+ end
464
+ end
465
+ end
466
+
467
+ context "waiting for the SERVICE_PAUSE_PENDING => SERVICE_PAUSED transition to finish before resuming it" do
468
+ before(:each) do
469
+ # This mocks the status query to return the SERVICE_RUNNING state by default.
470
+ # Otherwise, we will fail the tests in the latter parts of the code where we
471
+ # wait for the service to finish transitioning to the 'SERVICE_RUNNING' state.
472
+ subject::SERVICE_STATUS_PROCESS.stubs(:new).returns(dwCurrentState: subject::SERVICE_RUNNING)
473
+
474
+ expect_successful_status_query_and_return(dwCurrentState: subject::SERVICE_PAUSE_PENDING)
475
+
476
+ subject.stubs(:ControlService).returns(1)
477
+ end
478
+
479
+ include_examples "a service action waiting on a pending transition", service::SERVICE_PAUSE_PENDING do
480
+ let(:action) { :resume }
481
+ end
482
+ end
483
+
484
+ it "raises a Puppet::Error if ControlService returns false" do
485
+ expect_successful_status_query_and_return(dwCurrentState: subject::SERVICE_PAUSED)
486
+ expect_successful_status_query_and_return(dwCurrentState: subject::SERVICE_PAUSED)
487
+
488
+ subject.stubs(:ControlService).returns(FFI::WIN32_FALSE)
489
+
490
+ expect { subject.resume(mock_service_name, timeout: timeout) }.to raise_error(Puppet::Error)
491
+ end
492
+
493
+ it "resumes the service" do
494
+ expect_successful_status_queries_and_return(
495
+ { dwCurrentState: subject::SERVICE_PAUSED },
496
+ { dwCurrentState: subject::SERVICE_PAUSED },
497
+ { dwCurrentState: subject::SERVICE_RUNNING }
498
+ )
499
+
500
+ subject.expects(:ControlService).returns(1)
501
+
502
+ subject.resume(mock_service_name, timeout: timeout)
257
503
  end
258
504
  end
259
505
  end