win32-service 0.8.6 → 0.8.7

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.
@@ -1,121 +1,130 @@
1
- require 'ffi'
2
-
3
- module Windows
4
- module Structs
5
- extend FFI::Library
6
-
7
- typedef :ulong, :dword
8
-
9
- class SERVICE_STATUS < FFI::Struct
10
- layout(
11
- :dwServiceType, :ulong,
12
- :dwCurrentState, :ulong,
13
- :dwControlsAccepted, :ulong,
14
- :dwWin32ExitCode, :ulong,
15
- :dwServiceSpecificExitCode, :ulong,
16
- :dwCheckPoint, :ulong,
17
- :dwWaitHint, :ulong
18
- )
19
- end
20
-
21
- class SERVICE_STATUS_PROCESS < FFI::Struct
22
- layout(
23
- :dwServiceType, :dword,
24
- :dwCurrentState, :dword,
25
- :dwControlsAccepted, :dword,
26
- :dwWin32ExitCode, :dword,
27
- :dwServiceSpecificExitCode, :dword,
28
- :dwCheckPoint, :dword,
29
- :dwWaitHint, :dword,
30
- :dwProcessId, :dword,
31
- :dwServiceFlags, :dword
32
- )
33
- end
34
-
35
- class SERVICE_DESCRIPTION < FFI::Struct
36
- layout(:lpDescription, :pointer)
37
- end
38
-
39
- class SERVICE_DELAYED_AUTO_START_INFO < FFI::Struct
40
- layout(:fDelayedAutostart, :bool)
41
- end
42
-
43
- class QUERY_SERVICE_CONFIG < FFI::Struct
44
- layout(
45
- :dwServiceType, :dword,
46
- :dwStartType, :dword,
47
- :dwErrorControl, :dword,
48
- :lpBinaryPathName, :pointer,
49
- :lpLoadOrderGroup, :pointer,
50
- :dwTagId, :dword,
51
- :lpDependencies, :pointer,
52
- :lpServiceStartName, :pointer,
53
- :lpDisplayName, :pointer
54
- )
55
- end
56
-
57
- class SERVICE_STATUS_PROCESS < FFI::Struct
58
- layout(
59
- :dwServiceType, :dword,
60
- :dwCurrentState, :dword,
61
- :dwControlsAccepted, :dword,
62
- :dwWin32ExitCode, :dword,
63
- :dwServiceSpecificExitCode, :dword,
64
- :dwCheckPoint, :dword,
65
- :dwWaitHint, :dword,
66
- :dwProcessId, :dword,
67
- :dwServiceFlags, :dword
68
- )
69
- end
70
-
71
- class ENUM_SERVICE_STATUS_PROCESS < FFI::Struct
72
- layout(
73
- :lpServiceName, :pointer,
74
- :lpDisplayName, :pointer,
75
- :ServiceStatusProcess, SERVICE_STATUS_PROCESS
76
- )
77
- end
78
-
79
- class SC_ACTION < FFI::Struct
80
- layout(:Type, :int, :Delay, :dword)
81
- end
82
-
83
- class SERVICE_FAILURE_ACTIONS < FFI::Struct
84
- layout(
85
- :dwResetPeriod, :dword,
86
- :lpRebootMsg, :pointer,
87
- :lpCommand, :pointer,
88
- :cActions, :dword,
89
- :lpsaActions, :pointer # Array of SC_ACTION structs
90
- )
91
- end
92
-
93
- class SERVICE_TABLE_ENTRY < FFI::Struct
94
- layout(
95
- :lpServiceName, :pointer,
96
- :lpServiceProc, :pointer
97
- )
98
- end
99
-
100
- class LUID < FFI::Struct
101
- layout(
102
- :LowPart, :ulong,
103
- :HighPart, :long
104
- )
105
- end
106
-
107
- class LUID_AND_ATTRIBUTES < FFI::Struct
108
- layout(
109
- :Luid, LUID,
110
- :Attributes, :ulong
111
- )
112
- end
113
-
114
- class TOKEN_PRIVILEGES < FFI::Struct
115
- layout(
116
- :PrivilegeCount, :dword,
117
- :Privileges, [LUID_AND_ATTRIBUTES, 1]
118
- )
119
- end
120
- end
121
- end
1
+ require 'ffi'
2
+
3
+ module Windows
4
+ module Structs
5
+ extend FFI::Library
6
+
7
+ typedef :ulong, :dword
8
+
9
+ class SERVICE_STATUS < FFI::Struct
10
+ layout(
11
+ :dwServiceType, :ulong,
12
+ :dwCurrentState, :ulong,
13
+ :dwControlsAccepted, :ulong,
14
+ :dwWin32ExitCode, :ulong,
15
+ :dwServiceSpecificExitCode, :ulong,
16
+ :dwCheckPoint, :ulong,
17
+ :dwWaitHint, :ulong
18
+ )
19
+ end
20
+
21
+ class SERVICE_STATUS_PROCESS < FFI::Struct
22
+ layout(
23
+ :dwServiceType, :dword,
24
+ :dwCurrentState, :dword,
25
+ :dwControlsAccepted, :dword,
26
+ :dwWin32ExitCode, :dword,
27
+ :dwServiceSpecificExitCode, :dword,
28
+ :dwCheckPoint, :dword,
29
+ :dwWaitHint, :dword,
30
+ :dwProcessId, :dword,
31
+ :dwServiceFlags, :dword
32
+ )
33
+ end
34
+
35
+ class SERVICE_DESCRIPTION < FFI::Struct
36
+ layout(:lpDescription, :pointer)
37
+ end
38
+
39
+ class SERVICE_DELAYED_AUTO_START_INFO < FFI::Struct
40
+ layout(:fDelayedAutostart, :int) # BOOL
41
+
42
+ alias aset []=
43
+
44
+ # Intercept the accessor so that we can handle either true/false or 1/0.
45
+ # Since there is only one member, there's no need to check the key name.
46
+ #
47
+ def []=(key, value)
48
+ [0, false].include?(value) ? aset(key, 0) : aset(key, 1)
49
+ end
50
+ end
51
+
52
+ class QUERY_SERVICE_CONFIG < FFI::Struct
53
+ layout(
54
+ :dwServiceType, :dword,
55
+ :dwStartType, :dword,
56
+ :dwErrorControl, :dword,
57
+ :lpBinaryPathName, :pointer,
58
+ :lpLoadOrderGroup, :pointer,
59
+ :dwTagId, :dword,
60
+ :lpDependencies, :pointer,
61
+ :lpServiceStartName, :pointer,
62
+ :lpDisplayName, :pointer
63
+ )
64
+ end
65
+
66
+ class SERVICE_STATUS_PROCESS < FFI::Struct
67
+ layout(
68
+ :dwServiceType, :dword,
69
+ :dwCurrentState, :dword,
70
+ :dwControlsAccepted, :dword,
71
+ :dwWin32ExitCode, :dword,
72
+ :dwServiceSpecificExitCode, :dword,
73
+ :dwCheckPoint, :dword,
74
+ :dwWaitHint, :dword,
75
+ :dwProcessId, :dword,
76
+ :dwServiceFlags, :dword
77
+ )
78
+ end
79
+
80
+ class ENUM_SERVICE_STATUS_PROCESS < FFI::Struct
81
+ layout(
82
+ :lpServiceName, :pointer,
83
+ :lpDisplayName, :pointer,
84
+ :ServiceStatusProcess, SERVICE_STATUS_PROCESS
85
+ )
86
+ end
87
+
88
+ class SC_ACTION < FFI::Struct
89
+ layout(:Type, :int, :Delay, :dword)
90
+ end
91
+
92
+ class SERVICE_FAILURE_ACTIONS < FFI::Struct
93
+ layout(
94
+ :dwResetPeriod, :dword,
95
+ :lpRebootMsg, :pointer,
96
+ :lpCommand, :pointer,
97
+ :cActions, :dword,
98
+ :lpsaActions, :pointer # Array of SC_ACTION structs
99
+ )
100
+ end
101
+
102
+ class SERVICE_TABLE_ENTRY < FFI::Struct
103
+ layout(
104
+ :lpServiceName, :pointer,
105
+ :lpServiceProc, :pointer
106
+ )
107
+ end
108
+
109
+ class LUID < FFI::Struct
110
+ layout(
111
+ :LowPart, :ulong,
112
+ :HighPart, :long
113
+ )
114
+ end
115
+
116
+ class LUID_AND_ATTRIBUTES < FFI::Struct
117
+ layout(
118
+ :Luid, LUID,
119
+ :Attributes, :ulong
120
+ )
121
+ end
122
+
123
+ class TOKEN_PRIVILEGES < FFI::Struct
124
+ layout(
125
+ :PrivilegeCount, :dword,
126
+ :Privileges, [LUID_AND_ATTRIBUTES, 1]
127
+ )
128
+ end
129
+ end
130
+ end
@@ -1,58 +1,58 @@
1
- #########################################################################
2
- # test_win32_daemon.rb
3
- #
4
- # Test suite for the Win32::Daemon class. You should run this test via
5
- # the 'rake test' or 'rake test_daemon' tasks.
6
- #
7
- # These tests are rather limited, since the acid test is to install
8
- # your daemon as a service and see how it behaves.
9
- #########################################################################
10
- require 'test-unit'
11
- require 'win32/daemon'
12
- include Win32
13
-
14
- class TC_Daemon < Test::Unit::TestCase
15
- def setup
16
- @daemon = Daemon.new
17
- end
18
-
19
- test "version number is set properly" do
20
- assert_equal('0.8.4', Daemon::VERSION)
21
- end
22
-
23
- test "constructor basic functionality" do
24
- assert_respond_to(Daemon, :new)
25
- assert_nothing_raised{ Daemon.new }
26
- end
27
-
28
- test "constructor does not accept any arguments" do
29
- assert_raises(ArgumentError){ Daemon.new(1) }
30
- end
31
-
32
- test "mainloop basic functionality" do
33
- assert_respond_to(@daemon, :mainloop)
34
- end
35
-
36
- test "state basic functionality" do
37
- assert_respond_to(@daemon, :state)
38
- end
39
-
40
- test "is_running basic functionality" do
41
- assert_respond_to(@daemon, :running?)
42
- end
43
-
44
- test "expected constants are defined" do
45
- assert_not_nil(Daemon::CONTINUE_PENDING)
46
- assert_not_nil(Daemon::PAUSE_PENDING)
47
- assert_not_nil(Daemon::PAUSED)
48
- assert_not_nil(Daemon::RUNNING)
49
- assert_not_nil(Daemon::START_PENDING)
50
- assert_not_nil(Daemon::STOP_PENDING)
51
- assert_not_nil(Daemon::STOPPED)
52
- assert_not_nil(Daemon::IDLE)
53
- end
54
-
55
- def teardown
56
- @daemon = nil
57
- end
58
- end
1
+ #########################################################################
2
+ # test_win32_daemon.rb
3
+ #
4
+ # Test suite for the Win32::Daemon class. You should run this test via
5
+ # the 'rake test' or 'rake test_daemon' tasks.
6
+ #
7
+ # These tests are rather limited, since the acid test is to install
8
+ # your daemon as a service and see how it behaves.
9
+ #########################################################################
10
+ require 'test-unit'
11
+ require 'win32/daemon'
12
+ include Win32
13
+
14
+ class TC_Daemon < Test::Unit::TestCase
15
+ def setup
16
+ @daemon = Daemon.new
17
+ end
18
+
19
+ test "version number is set properly" do
20
+ assert_equal('0.8.6', Daemon::VERSION)
21
+ end
22
+
23
+ test "constructor basic functionality" do
24
+ assert_respond_to(Daemon, :new)
25
+ assert_nothing_raised{ Daemon.new }
26
+ end
27
+
28
+ test "constructor does not accept any arguments" do
29
+ assert_raises(ArgumentError){ Daemon.new(1) }
30
+ end
31
+
32
+ test "mainloop basic functionality" do
33
+ assert_respond_to(@daemon, :mainloop)
34
+ end
35
+
36
+ test "state basic functionality" do
37
+ assert_respond_to(@daemon, :state)
38
+ end
39
+
40
+ test "is_running basic functionality" do
41
+ assert_respond_to(@daemon, :running?)
42
+ end
43
+
44
+ test "expected constants are defined" do
45
+ assert_not_nil(Daemon::CONTINUE_PENDING)
46
+ assert_not_nil(Daemon::PAUSE_PENDING)
47
+ assert_not_nil(Daemon::PAUSED)
48
+ assert_not_nil(Daemon::RUNNING)
49
+ assert_not_nil(Daemon::START_PENDING)
50
+ assert_not_nil(Daemon::STOP_PENDING)
51
+ assert_not_nil(Daemon::STOPPED)
52
+ assert_not_nil(Daemon::IDLE)
53
+ end
54
+
55
+ def teardown
56
+ @daemon = nil
57
+ end
58
+ end
@@ -1,437 +1,437 @@
1
- ##########################################################################
2
- # test_win32_service.rb
3
- #
4
- # Tests for the Win32::Service class.
5
- ##########################################################################
6
- require 'test-unit'
7
- require 'win32/security'
8
- require 'win32/service'
9
- require 'socket'
10
-
11
- class TC_Win32_Service < Test::Unit::TestCase
12
- def self.startup
13
- @@host = Socket.gethostname
14
- @@service_name = 'stisvc'
15
- @@elevated = Win32::Security.elevated_security?
16
- end
17
-
18
- def setup
19
- @display_name = 'Windows Image Acquisition (WIA)'
20
- @service_name = 'stisvc'
21
- @service_stat = nil
22
- @services = []
23
-
24
- @singleton_methods = Win32::Service.methods.map{ |m| m.to_s }
25
- @instance_methods = Win32::Service.instance_methods.map{ |m| m.to_s }
26
- end
27
-
28
- def start_service(service)
29
- status = Win32::Service.status(@service_name).current_state
30
- if status == 'paused'
31
- Win32::Service.resume(service)
32
- else
33
- unless ['running', 'start pending'].include?(status)
34
- Win32::Service.start(service)
35
- end
36
- end
37
- wait_for_status('running')
38
- end
39
-
40
- def stop_service(service)
41
- status = Win32::Service.status(@service_name).current_state
42
- unless ['stopped', 'stop pending'].include?(status)
43
- Win32::Service.stop(service)
44
- end
45
- wait_for_status('stopped')
46
- end
47
-
48
- # Helper method that waits for a status to change its state since state
49
- # changes aren't usually instantaneous.
50
- def wait_for_status(status)
51
- sleep 0.1 while Win32::Service.status(@service_name).current_state != status
52
- end
53
-
54
- test "version number is expected value" do
55
- assert_equal('0.8.5', Win32::Service::VERSION)
56
- end
57
-
58
- test "services basic functionality" do
59
- assert_respond_to(Win32::Service, :services)
60
- assert_nothing_raised{ Win32::Service.services }
61
- assert_nothing_raised{ Win32::Service.services(nil) }
62
- assert_nothing_raised{ Win32::Service.services(nil, 'network') }
63
- end
64
-
65
- test "services method returns an array without a block" do
66
- assert_nothing_raised{ @services = Win32::Service.services }
67
- assert_kind_of(Array, @services)
68
- assert_kind_of(Struct::ServiceInfo, @services[0])
69
- end
70
-
71
- test "services method yields service objects when a block is provided" do
72
- assert_nothing_raised{ Win32::Service.services{ |s| @services << s } }
73
- assert_kind_of(Array, @services)
74
- assert_kind_of(Struct::ServiceInfo, @services[0])
75
- end
76
-
77
- test "the host argument must be a string or an error is raised" do
78
- assert_raise(TypeError){ Win32::Service.services(1) }
79
- end
80
-
81
- test "the group argument must be a string or an error is raised" do
82
- assert_raise(TypeError){ Win32::Service.services(nil, 1) }
83
- end
84
-
85
- test "the services method only accepts 2 arguments" do
86
- assert_raise(ArgumentError){ Win32::Service.services(nil, 'network', 1) }
87
- end
88
-
89
- test "a valid hostname must be provided or an error is raised" do
90
- assert_raise(SystemCallError){ Win32::Service.services('bogus') }
91
- end
92
-
93
- test "delete method basic functionality" do
94
- assert_respond_to(Win32::Service, :delete)
95
- end
96
-
97
- test "a service name must be provided to the delete method" do
98
- assert_raise(ArgumentError){ Win32::Service.delete }
99
- end
100
-
101
- test "delete method raises an error if a bogus service name is provided" do
102
- omit_unless(@@elevated, "Skipped unless run with admin privileges")
103
- assert_raise(SystemCallError){ Win32::Service.delete('bogus') }
104
- end
105
-
106
- test "delete method raises an error if a bogus host name is provided" do
107
- assert_raise(SystemCallError){ Win32::Service.delete('bogus', 'bogus') }
108
- end
109
-
110
- test "delete method only accepts up to two arguments" do
111
- assert_raise(ArgumentError){ Win32::Service.delete('x', 'y', 'z') }
112
- end
113
-
114
- test "pause basic functionality" do
115
- assert_respond_to(Win32::Service, :pause)
116
- end
117
-
118
- test "resume basic functionality" do
119
- assert_respond_to(Win32::Service, :resume)
120
- end
121
-
122
- test "pause and resume work as expected" do
123
- omit_unless(@@elevated, "Skipped unless run with admin privileges")
124
- start_service(@service_name)
125
-
126
- assert_nothing_raised{ Win32::Service.pause(@service_name) }
127
- wait_for_status('paused')
128
-
129
- assert_nothing_raised{ Win32::Service.resume(@service_name) }
130
- wait_for_status('running')
131
- end
132
-
133
- test "pausing an already paused service is harmless" do
134
- omit_unless(@@elevated, "Skipped unless run with admin privileges")
135
- start_service(@service_name)
136
-
137
- assert_nothing_raised{ Win32::Service.pause(@service_name) }
138
- wait_for_status('paused')
139
- assert_nothing_raised{ Win32::Service.pause(@service_name) }
140
- end
141
-
142
- test "pause requires a service name as an argument" do
143
- assert_raise(ArgumentError){ Win32::Service.pause }
144
- end
145
-
146
- test "pausing an unrecognized service name raises an error" do
147
- assert_raise(SystemCallError){ Win32::Service.pause('bogus') }
148
- end
149
-
150
- test "pausing a service on an unrecognized host raises an error" do
151
- assert_raise(SystemCallError){ Win32::Service.pause('W32Time', 'bogus') }
152
- end
153
-
154
- test "pause method accepts a maximum of two arguments" do
155
- assert_raise(ArgumentError){ Win32::Service.pause('x', 'y', 'z') }
156
- end
157
-
158
- test "resume method requires a service name" do
159
- assert_raise(ArgumentError){ Win32::Service.resume }
160
- end
161
-
162
- test "resume method with an unrecognized service name raises an error" do
163
- assert_raise(SystemCallError){ Win32::Service.resume('bogus') }
164
- end
165
-
166
- test "resume method with an unrecognized host name raises an error" do
167
- assert_raise(SystemCallError){ Win32::Service.resume('W32Time', 'bogus') }
168
- end
169
-
170
- test "resume method accepts a maximum of two arguments" do
171
- assert_raise(ArgumentError){ Win32::Service.resume('W32Time', @@host, true) }
172
- end
173
-
174
- test "stop method basic functionality" do
175
- assert_respond_to(Win32::Service, :stop)
176
- end
177
-
178
- test "start method basic functionality" do
179
- assert_respond_to(Win32::Service, :start)
180
- end
181
-
182
- test "stop and start methods work as expected" do
183
- omit_unless(@@elevated, "Skipped unless run with admin privileges")
184
- start_service(@service_name)
185
-
186
- assert_nothing_raised{ Win32::Service.stop(@service_name) }
187
- wait_for_status('stopped')
188
-
189
- assert_nothing_raised{ Win32::Service.start(@service_name) }
190
- wait_for_status('running')
191
- end
192
-
193
- test "attempting to stop a stopped service raises an error" do
194
- omit_unless(@@elevated, "Skipped unless run with admin privileges")
195
- start_service(@service_name)
196
-
197
- assert_nothing_raised{ Win32::Service.stop(@service_name) }
198
- wait_for_status('stopped')
199
- assert_raise(SystemCallError){ Win32::Service.stop(@service_name) }
200
-
201
- assert_nothing_raised{ Win32::Service.start(@service_name) }
202
- end
203
-
204
- test "stop method requires a service name" do
205
- assert_raise(ArgumentError){ Win32::Service.stop }
206
- end
207
-
208
- test "stop method raises an error if the service name is unrecognized" do
209
- assert_raise(SystemCallError){ Win32::Service.stop('bogus') }
210
- end
211
-
212
- test "stop method raises an error if the host is unrecognized" do
213
- assert_raise(SystemCallError){ Win32::Service.stop('W32Time', 'bogus') }
214
- end
215
-
216
- test "stop metho accepts a maximum of two arguments" do
217
- assert_raise(ArgumentError){ Win32::Service.stop('W32Time', @@host, true) }
218
- end
219
-
220
- test "start method requires a service name" do
221
- assert_raise(ArgumentError){ Win32::Service.start }
222
- end
223
-
224
- test "attempting to start a running service raises an error" do
225
- omit_unless(@@elevated, "Skipped unless run with admin privileges")
226
- start_service(@service_name)
227
- assert_raise(SystemCallError){ Win32::Service.start(@service_name) }
228
- end
229
-
230
- test "attempting to start an unrecognized service raises an error" do
231
- assert_raise(SystemCallError){ Win32::Service.start('bogus') }
232
- end
233
-
234
- test "attempting to start a service on an unknown host raises an error" do
235
- assert_raise(SystemCallError){ Win32::Service.start('bogus', 'bogus') }
236
- end
237
-
238
- test "stop requires at least one argument" do
239
- assert_raise(ArgumentError){ Win32::Service.stop }
240
- end
241
-
242
- test "stop raises an error with an unrecognized service name" do
243
- assert_raise(SystemCallError){ Win32::Service.stop('bogus') }
244
- end
245
-
246
- test "stop raises an error with an unrecognized host" do
247
- assert_raise(SystemCallError){ Win32::Service.stop('W32Time', 'bogus') }
248
- end
249
-
250
- test "stop accepts a maximum of 2 arguments" do
251
- assert_raise(ArgumentError){ Win32::Service.stop('a', 'b', 'c') }
252
- end
253
-
254
- test "status basic functionality" do
255
- assert_respond_to(Win32::Service, :status)
256
- assert_nothing_raised{ Win32::Service.status(@service_name) }
257
- assert_kind_of(Struct::ServiceStatus, Win32::Service.status(@service_name))
258
- end
259
-
260
- test "get_service_name basic functionality" do
261
- assert_respond_to(Win32::Service, :get_service_name)
262
- assert_nothing_raised{ Win32::Service.get_service_name(@display_name) }
263
- assert_kind_of(String, Win32::Service.get_service_name(@display_name))
264
- end
265
-
266
- test "get_service_name returns expected results" do
267
- assert_equal(@service_name, Win32::Service.get_service_name(@display_name))
268
- end
269
-
270
- test "getservicename is an alias for get_service_name" do
271
- assert_respond_to(Win32::Service, :getservicename)
272
- assert_alias_method(Win32::Service, :getservicename, :get_service_name)
273
- end
274
-
275
- test "get_service_name requires at least one argument" do
276
- assert_raise(ArgumentError){ Win32::Service.get_service_name }
277
- end
278
-
279
- test "get_service_name raises an error if a bogus service name is provided" do
280
- assert_raise(SystemCallError){ Win32::Service.get_service_name('bogus') }
281
- end
282
-
283
- test "get_service_name raises an error if a bogus host is provided" do
284
- assert_raise(SystemCallError){ Win32::Service.get_service_name('foo', 'bogus') }
285
- end
286
-
287
- test "get_service_name accepts a maximum of two arguments" do
288
- assert_raise(ArgumentError){ Win32::Service.get_service_name('x', 'y', 'z') }
289
- end
290
-
291
- test "get_display_name basic functionality" do
292
- assert_respond_to(Win32::Service, :get_display_name)
293
- assert_nothing_raised{ Win32::Service.get_display_name(@service_name) }
294
- assert_kind_of(String, Win32::Service.get_display_name(@service_name))
295
- end
296
-
297
- test "get_display_name returns expected results" do
298
- assert_equal(@display_name, Win32::Service.get_display_name(@service_name))
299
- end
300
-
301
- test "getdisplayname is an alias for get_display_name" do
302
- assert_respond_to(Win32::Service, :getdisplayname)
303
- assert_alias_method(Win32::Service, :getdisplayname, :get_display_name)
304
- end
305
-
306
- test "get_display_name requires at least one argument" do
307
- assert_raise(ArgumentError){ Win32::Service.get_display_name }
308
- end
309
-
310
- test "get_display_name raises an error if the service does not exist" do
311
- assert_raise(SystemCallError){ Win32::Service.get_display_name('bogus') }
312
- end
313
-
314
- test "get_display_name raises an error if a bad host name is provided" do
315
- assert_raise(SystemCallError){ Win32::Service.get_display_name('W32Time', 'bogus') }
316
- end
317
-
318
- test "get_display_name takes a maximum of two arguments" do
319
- assert_raise(ArgumentError){ Win32::Service.get_display_name('x', 'y', 'z') }
320
- end
321
-
322
- test "exists method basic functionality" do
323
- assert_respond_to(Win32::Service, :exists?)
324
- assert_boolean(Win32::Service.exists?('W32Time'))
325
- assert_nothing_raised{ Win32::Service.exists?('W32Time') }
326
- end
327
-
328
- test "exists method returns expected results" do
329
- assert_true(Win32::Service.exists?('W32Time'))
330
- assert_false(Win32::Service.exists?('foobar'))
331
- end
332
-
333
- test "exists method requires at least one argument or an error is raised" do
334
- assert_raises(ArgumentError){ Win32::Service.exists? }
335
- end
336
-
337
- test "exists method raises an error if a bogus host is passed" do
338
- assert_raises(SystemCallError){
339
- Win32::Service.exists?('foo', 'bogushost')
340
- }
341
- end
342
-
343
- test "exists method only accepts up to two arguments" do
344
- assert_raises(ArgumentError){
345
- Win32::Service.exists?('foo', 'bar', 'baz')
346
- }
347
- end
348
-
349
- test "scm security constants are defined" do
350
- assert_not_nil(Win32::Service::MANAGER_ALL_ACCESS)
351
- assert_not_nil(Win32::Service::MANAGER_CREATE_SERVICE)
352
- assert_not_nil(Win32::Service::MANAGER_CONNECT)
353
- assert_not_nil(Win32::Service::MANAGER_ENUMERATE_SERVICE)
354
- assert_not_nil(Win32::Service::MANAGER_LOCK)
355
- assert_not_nil(Win32::Service::MANAGER_QUERY_LOCK_STATUS)
356
- end
357
-
358
- test "service specific constants are defined" do
359
- assert_not_nil(Win32::Service::ALL_ACCESS)
360
- assert_not_nil(Win32::Service::CHANGE_CONFIG)
361
- assert_not_nil(Win32::Service::ENUMERATE_DEPENDENTS)
362
- assert_not_nil(Win32::Service::INTERROGATE)
363
- assert_not_nil(Win32::Service::PAUSE_CONTINUE)
364
- assert_not_nil(Win32::Service::QUERY_CONFIG)
365
- assert_not_nil(Win32::Service::QUERY_STATUS)
366
- assert_not_nil(Win32::Service::STOP)
367
- assert_not_nil(Win32::Service::START)
368
- assert_not_nil(Win32::Service::USER_DEFINED_CONTROL)
369
- end
370
-
371
- test "service type constants are defined" do
372
- assert_not_nil(Win32::Service::FILE_SYSTEM_DRIVER)
373
- assert_not_nil(Win32::Service::KERNEL_DRIVER)
374
- assert_not_nil(Win32::Service::WIN32_OWN_PROCESS)
375
- assert_not_nil(Win32::Service::WIN32_SHARE_PROCESS)
376
- assert_not_nil(Win32::Service::INTERACTIVE_PROCESS)
377
- end
378
-
379
- test "service start option constants are defined" do
380
- assert_not_nil(Win32::Service::AUTO_START)
381
- assert_not_nil(Win32::Service::BOOT_START)
382
- assert_not_nil(Win32::Service::DEMAND_START)
383
- assert_not_nil(Win32::Service::DISABLED)
384
- assert_not_nil(Win32::Service::SYSTEM_START)
385
- end
386
-
387
- test "service error control constants are defined" do
388
- assert_not_nil(Win32::Service::ERROR_IGNORE)
389
- assert_not_nil(Win32::Service::ERROR_NORMAL)
390
- assert_not_nil(Win32::Service::ERROR_SEVERE)
391
- assert_not_nil(Win32::Service::ERROR_CRITICAL)
392
- end
393
-
394
- test "service state constants are defined" do
395
- assert_not_nil(Win32::Service::CONTINUE_PENDING)
396
- assert_not_nil(Win32::Service::PAUSE_PENDING)
397
- assert_not_nil(Win32::Service::PAUSED)
398
- assert_not_nil(Win32::Service::RUNNING)
399
- assert_not_nil(Win32::Service::START_PENDING)
400
- assert_not_nil(Win32::Service::STOP_PENDING)
401
- assert_not_nil(Win32::Service::STOPPED)
402
- end
403
-
404
- test "internal ffi functions are not public as singleton methods" do
405
- assert_false(@singleton_methods.include?('CloseHandle'))
406
- assert_false(@singleton_methods.include?('ControlService'))
407
- assert_false(@singleton_methods.include?('DeleteService'))
408
- end
409
-
410
- test "internal ffi functions are not public as instance methods" do
411
- assert_false(@instance_methods.include?('CloseHandle'))
412
- assert_false(@instance_methods.include?('ControlService'))
413
- assert_false(@instance_methods.include?('DeleteService'))
414
- end
415
-
416
- def teardown
417
- @display_name = nil
418
- @service_name = nil
419
- @service_stat = nil
420
- @services = nil
421
- end
422
-
423
- def self.shutdown
424
- @@host = nil
425
- status = Win32::Service.status(@@service_name).current_state
426
-
427
- if status == 'paused'
428
- Win32::Service.resume(@@service_name)
429
- end
430
-
431
- unless ['running', 'start pending'].include?(status)
432
- Win32::Service.start(@@service_name)
433
- end
434
-
435
- @@elevated = nil
436
- end
437
- end
1
+ ##########################################################################
2
+ # test_win32_service.rb
3
+ #
4
+ # Tests for the Win32::Service class.
5
+ ##########################################################################
6
+ require 'test-unit'
7
+ require 'win32/security'
8
+ require 'win32/service'
9
+ require 'socket'
10
+
11
+ class TC_Win32_Service < Test::Unit::TestCase
12
+ def self.startup
13
+ @@host = Socket.gethostname
14
+ @@service_name = 'stisvc'
15
+ @@elevated = Win32::Security.elevated_security?
16
+ end
17
+
18
+ def setup
19
+ @display_name = 'Windows Image Acquisition (WIA)'
20
+ @service_name = 'stisvc'
21
+ @service_stat = nil
22
+ @services = []
23
+
24
+ @singleton_methods = Win32::Service.methods.map{ |m| m.to_s }
25
+ @instance_methods = Win32::Service.instance_methods.map{ |m| m.to_s }
26
+ end
27
+
28
+ def start_service(service)
29
+ status = Win32::Service.status(@service_name).current_state
30
+ if status == 'paused'
31
+ Win32::Service.resume(service)
32
+ else
33
+ unless ['running', 'start pending'].include?(status)
34
+ Win32::Service.start(service)
35
+ end
36
+ end
37
+ wait_for_status('running')
38
+ end
39
+
40
+ def stop_service(service)
41
+ status = Win32::Service.status(@service_name).current_state
42
+ unless ['stopped', 'stop pending'].include?(status)
43
+ Win32::Service.stop(service)
44
+ end
45
+ wait_for_status('stopped')
46
+ end
47
+
48
+ # Helper method that waits for a status to change its state since state
49
+ # changes aren't usually instantaneous.
50
+ def wait_for_status(status)
51
+ sleep 0.1 while Win32::Service.status(@service_name).current_state != status
52
+ end
53
+
54
+ test "version number is expected value" do
55
+ assert_equal('0.8.7', Win32::Service::VERSION)
56
+ end
57
+
58
+ test "services basic functionality" do
59
+ assert_respond_to(Win32::Service, :services)
60
+ assert_nothing_raised{ Win32::Service.services }
61
+ assert_nothing_raised{ Win32::Service.services(nil) }
62
+ assert_nothing_raised{ Win32::Service.services(nil, 'network') }
63
+ end
64
+
65
+ test "services method returns an array without a block" do
66
+ assert_nothing_raised{ @services = Win32::Service.services }
67
+ assert_kind_of(Array, @services)
68
+ assert_kind_of(Struct::ServiceInfo, @services[0])
69
+ end
70
+
71
+ test "services method yields service objects when a block is provided" do
72
+ assert_nothing_raised{ Win32::Service.services{ |s| @services << s } }
73
+ assert_kind_of(Array, @services)
74
+ assert_kind_of(Struct::ServiceInfo, @services[0])
75
+ end
76
+
77
+ test "the host argument must be a string or an error is raised" do
78
+ assert_raise(TypeError){ Win32::Service.services(1) }
79
+ end
80
+
81
+ test "the group argument must be a string or an error is raised" do
82
+ assert_raise(TypeError){ Win32::Service.services(nil, 1) }
83
+ end
84
+
85
+ test "the services method only accepts 2 arguments" do
86
+ assert_raise(ArgumentError){ Win32::Service.services(nil, 'network', 1) }
87
+ end
88
+
89
+ test "a valid hostname must be provided or an error is raised" do
90
+ assert_raise(SystemCallError){ Win32::Service.services('bogus') }
91
+ end
92
+
93
+ test "delete method basic functionality" do
94
+ assert_respond_to(Win32::Service, :delete)
95
+ end
96
+
97
+ test "a service name must be provided to the delete method" do
98
+ assert_raise(ArgumentError){ Win32::Service.delete }
99
+ end
100
+
101
+ test "delete method raises an error if a bogus service name is provided" do
102
+ omit_unless(@@elevated, "Skipped unless run with admin privileges")
103
+ assert_raise(SystemCallError){ Win32::Service.delete('bogus') }
104
+ end
105
+
106
+ test "delete method raises an error if a bogus host name is provided" do
107
+ assert_raise(SystemCallError){ Win32::Service.delete('bogus', 'bogus') }
108
+ end
109
+
110
+ test "delete method only accepts up to two arguments" do
111
+ assert_raise(ArgumentError){ Win32::Service.delete('x', 'y', 'z') }
112
+ end
113
+
114
+ test "pause basic functionality" do
115
+ assert_respond_to(Win32::Service, :pause)
116
+ end
117
+
118
+ test "resume basic functionality" do
119
+ assert_respond_to(Win32::Service, :resume)
120
+ end
121
+
122
+ test "pause and resume work as expected" do
123
+ omit_unless(@@elevated, "Skipped unless run with admin privileges")
124
+ start_service(@service_name)
125
+
126
+ assert_nothing_raised{ Win32::Service.pause(@service_name) }
127
+ wait_for_status('paused')
128
+
129
+ assert_nothing_raised{ Win32::Service.resume(@service_name) }
130
+ wait_for_status('running')
131
+ end
132
+
133
+ test "pausing an already paused service is harmless" do
134
+ omit_unless(@@elevated, "Skipped unless run with admin privileges")
135
+ start_service(@service_name)
136
+
137
+ assert_nothing_raised{ Win32::Service.pause(@service_name) }
138
+ wait_for_status('paused')
139
+ assert_nothing_raised{ Win32::Service.pause(@service_name) }
140
+ end
141
+
142
+ test "pause requires a service name as an argument" do
143
+ assert_raise(ArgumentError){ Win32::Service.pause }
144
+ end
145
+
146
+ test "pausing an unrecognized service name raises an error" do
147
+ assert_raise(SystemCallError){ Win32::Service.pause('bogus') }
148
+ end
149
+
150
+ test "pausing a service on an unrecognized host raises an error" do
151
+ assert_raise(SystemCallError){ Win32::Service.pause('W32Time', 'bogus') }
152
+ end
153
+
154
+ test "pause method accepts a maximum of two arguments" do
155
+ assert_raise(ArgumentError){ Win32::Service.pause('x', 'y', 'z') }
156
+ end
157
+
158
+ test "resume method requires a service name" do
159
+ assert_raise(ArgumentError){ Win32::Service.resume }
160
+ end
161
+
162
+ test "resume method with an unrecognized service name raises an error" do
163
+ assert_raise(SystemCallError){ Win32::Service.resume('bogus') }
164
+ end
165
+
166
+ test "resume method with an unrecognized host name raises an error" do
167
+ assert_raise(SystemCallError){ Win32::Service.resume('W32Time', 'bogus') }
168
+ end
169
+
170
+ test "resume method accepts a maximum of two arguments" do
171
+ assert_raise(ArgumentError){ Win32::Service.resume('W32Time', @@host, true) }
172
+ end
173
+
174
+ test "stop method basic functionality" do
175
+ assert_respond_to(Win32::Service, :stop)
176
+ end
177
+
178
+ test "start method basic functionality" do
179
+ assert_respond_to(Win32::Service, :start)
180
+ end
181
+
182
+ test "stop and start methods work as expected" do
183
+ omit_unless(@@elevated, "Skipped unless run with admin privileges")
184
+ start_service(@service_name)
185
+
186
+ assert_nothing_raised{ Win32::Service.stop(@service_name) }
187
+ wait_for_status('stopped')
188
+
189
+ assert_nothing_raised{ Win32::Service.start(@service_name) }
190
+ wait_for_status('running')
191
+ end
192
+
193
+ test "attempting to stop a stopped service raises an error" do
194
+ omit_unless(@@elevated, "Skipped unless run with admin privileges")
195
+ start_service(@service_name)
196
+
197
+ assert_nothing_raised{ Win32::Service.stop(@service_name) }
198
+ wait_for_status('stopped')
199
+ assert_raise(SystemCallError){ Win32::Service.stop(@service_name) }
200
+
201
+ assert_nothing_raised{ Win32::Service.start(@service_name) }
202
+ end
203
+
204
+ test "stop method requires a service name" do
205
+ assert_raise(ArgumentError){ Win32::Service.stop }
206
+ end
207
+
208
+ test "stop method raises an error if the service name is unrecognized" do
209
+ assert_raise(SystemCallError){ Win32::Service.stop('bogus') }
210
+ end
211
+
212
+ test "stop method raises an error if the host is unrecognized" do
213
+ assert_raise(SystemCallError){ Win32::Service.stop('W32Time', 'bogus') }
214
+ end
215
+
216
+ test "stop metho accepts a maximum of two arguments" do
217
+ assert_raise(ArgumentError){ Win32::Service.stop('W32Time', @@host, true) }
218
+ end
219
+
220
+ test "start method requires a service name" do
221
+ assert_raise(ArgumentError){ Win32::Service.start }
222
+ end
223
+
224
+ test "attempting to start a running service raises an error" do
225
+ omit_unless(@@elevated, "Skipped unless run with admin privileges")
226
+ start_service(@service_name)
227
+ assert_raise(SystemCallError){ Win32::Service.start(@service_name) }
228
+ end
229
+
230
+ test "attempting to start an unrecognized service raises an error" do
231
+ assert_raise(SystemCallError){ Win32::Service.start('bogus') }
232
+ end
233
+
234
+ test "attempting to start a service on an unknown host raises an error" do
235
+ assert_raise(SystemCallError){ Win32::Service.start('bogus', 'bogus') }
236
+ end
237
+
238
+ test "stop requires at least one argument" do
239
+ assert_raise(ArgumentError){ Win32::Service.stop }
240
+ end
241
+
242
+ test "stop raises an error with an unrecognized service name" do
243
+ assert_raise(SystemCallError){ Win32::Service.stop('bogus') }
244
+ end
245
+
246
+ test "stop raises an error with an unrecognized host" do
247
+ assert_raise(SystemCallError){ Win32::Service.stop('W32Time', 'bogus') }
248
+ end
249
+
250
+ test "stop accepts a maximum of 2 arguments" do
251
+ assert_raise(ArgumentError){ Win32::Service.stop('a', 'b', 'c') }
252
+ end
253
+
254
+ test "status basic functionality" do
255
+ assert_respond_to(Win32::Service, :status)
256
+ assert_nothing_raised{ Win32::Service.status(@service_name) }
257
+ assert_kind_of(Struct::ServiceStatus, Win32::Service.status(@service_name))
258
+ end
259
+
260
+ test "get_service_name basic functionality" do
261
+ assert_respond_to(Win32::Service, :get_service_name)
262
+ assert_nothing_raised{ Win32::Service.get_service_name(@display_name) }
263
+ assert_kind_of(String, Win32::Service.get_service_name(@display_name))
264
+ end
265
+
266
+ test "get_service_name returns expected results" do
267
+ assert_equal(@service_name, Win32::Service.get_service_name(@display_name))
268
+ end
269
+
270
+ test "getservicename is an alias for get_service_name" do
271
+ assert_respond_to(Win32::Service, :getservicename)
272
+ assert_alias_method(Win32::Service, :getservicename, :get_service_name)
273
+ end
274
+
275
+ test "get_service_name requires at least one argument" do
276
+ assert_raise(ArgumentError){ Win32::Service.get_service_name }
277
+ end
278
+
279
+ test "get_service_name raises an error if a bogus service name is provided" do
280
+ assert_raise(SystemCallError){ Win32::Service.get_service_name('bogus') }
281
+ end
282
+
283
+ test "get_service_name raises an error if a bogus host is provided" do
284
+ assert_raise(SystemCallError){ Win32::Service.get_service_name('foo', 'bogus') }
285
+ end
286
+
287
+ test "get_service_name accepts a maximum of two arguments" do
288
+ assert_raise(ArgumentError){ Win32::Service.get_service_name('x', 'y', 'z') }
289
+ end
290
+
291
+ test "get_display_name basic functionality" do
292
+ assert_respond_to(Win32::Service, :get_display_name)
293
+ assert_nothing_raised{ Win32::Service.get_display_name(@service_name) }
294
+ assert_kind_of(String, Win32::Service.get_display_name(@service_name))
295
+ end
296
+
297
+ test "get_display_name returns expected results" do
298
+ assert_equal(@display_name, Win32::Service.get_display_name(@service_name))
299
+ end
300
+
301
+ test "getdisplayname is an alias for get_display_name" do
302
+ assert_respond_to(Win32::Service, :getdisplayname)
303
+ assert_alias_method(Win32::Service, :getdisplayname, :get_display_name)
304
+ end
305
+
306
+ test "get_display_name requires at least one argument" do
307
+ assert_raise(ArgumentError){ Win32::Service.get_display_name }
308
+ end
309
+
310
+ test "get_display_name raises an error if the service does not exist" do
311
+ assert_raise(SystemCallError){ Win32::Service.get_display_name('bogus') }
312
+ end
313
+
314
+ test "get_display_name raises an error if a bad host name is provided" do
315
+ assert_raise(SystemCallError){ Win32::Service.get_display_name('W32Time', 'bogus') }
316
+ end
317
+
318
+ test "get_display_name takes a maximum of two arguments" do
319
+ assert_raise(ArgumentError){ Win32::Service.get_display_name('x', 'y', 'z') }
320
+ end
321
+
322
+ test "exists method basic functionality" do
323
+ assert_respond_to(Win32::Service, :exists?)
324
+ assert_boolean(Win32::Service.exists?('W32Time'))
325
+ assert_nothing_raised{ Win32::Service.exists?('W32Time') }
326
+ end
327
+
328
+ test "exists method returns expected results" do
329
+ assert_true(Win32::Service.exists?('W32Time'))
330
+ assert_false(Win32::Service.exists?('foobar'))
331
+ end
332
+
333
+ test "exists method requires at least one argument or an error is raised" do
334
+ assert_raises(ArgumentError){ Win32::Service.exists? }
335
+ end
336
+
337
+ test "exists method raises an error if a bogus host is passed" do
338
+ assert_raises(SystemCallError){
339
+ Win32::Service.exists?('foo', 'bogushost')
340
+ }
341
+ end
342
+
343
+ test "exists method only accepts up to two arguments" do
344
+ assert_raises(ArgumentError){
345
+ Win32::Service.exists?('foo', 'bar', 'baz')
346
+ }
347
+ end
348
+
349
+ test "scm security constants are defined" do
350
+ assert_not_nil(Win32::Service::MANAGER_ALL_ACCESS)
351
+ assert_not_nil(Win32::Service::MANAGER_CREATE_SERVICE)
352
+ assert_not_nil(Win32::Service::MANAGER_CONNECT)
353
+ assert_not_nil(Win32::Service::MANAGER_ENUMERATE_SERVICE)
354
+ assert_not_nil(Win32::Service::MANAGER_LOCK)
355
+ assert_not_nil(Win32::Service::MANAGER_QUERY_LOCK_STATUS)
356
+ end
357
+
358
+ test "service specific constants are defined" do
359
+ assert_not_nil(Win32::Service::ALL_ACCESS)
360
+ assert_not_nil(Win32::Service::CHANGE_CONFIG)
361
+ assert_not_nil(Win32::Service::ENUMERATE_DEPENDENTS)
362
+ assert_not_nil(Win32::Service::INTERROGATE)
363
+ assert_not_nil(Win32::Service::PAUSE_CONTINUE)
364
+ assert_not_nil(Win32::Service::QUERY_CONFIG)
365
+ assert_not_nil(Win32::Service::QUERY_STATUS)
366
+ assert_not_nil(Win32::Service::STOP)
367
+ assert_not_nil(Win32::Service::START)
368
+ assert_not_nil(Win32::Service::USER_DEFINED_CONTROL)
369
+ end
370
+
371
+ test "service type constants are defined" do
372
+ assert_not_nil(Win32::Service::FILE_SYSTEM_DRIVER)
373
+ assert_not_nil(Win32::Service::KERNEL_DRIVER)
374
+ assert_not_nil(Win32::Service::WIN32_OWN_PROCESS)
375
+ assert_not_nil(Win32::Service::WIN32_SHARE_PROCESS)
376
+ assert_not_nil(Win32::Service::INTERACTIVE_PROCESS)
377
+ end
378
+
379
+ test "service start option constants are defined" do
380
+ assert_not_nil(Win32::Service::AUTO_START)
381
+ assert_not_nil(Win32::Service::BOOT_START)
382
+ assert_not_nil(Win32::Service::DEMAND_START)
383
+ assert_not_nil(Win32::Service::DISABLED)
384
+ assert_not_nil(Win32::Service::SYSTEM_START)
385
+ end
386
+
387
+ test "service error control constants are defined" do
388
+ assert_not_nil(Win32::Service::ERROR_IGNORE)
389
+ assert_not_nil(Win32::Service::ERROR_NORMAL)
390
+ assert_not_nil(Win32::Service::ERROR_SEVERE)
391
+ assert_not_nil(Win32::Service::ERROR_CRITICAL)
392
+ end
393
+
394
+ test "service state constants are defined" do
395
+ assert_not_nil(Win32::Service::CONTINUE_PENDING)
396
+ assert_not_nil(Win32::Service::PAUSE_PENDING)
397
+ assert_not_nil(Win32::Service::PAUSED)
398
+ assert_not_nil(Win32::Service::RUNNING)
399
+ assert_not_nil(Win32::Service::START_PENDING)
400
+ assert_not_nil(Win32::Service::STOP_PENDING)
401
+ assert_not_nil(Win32::Service::STOPPED)
402
+ end
403
+
404
+ test "internal ffi functions are not public as singleton methods" do
405
+ assert_false(@singleton_methods.include?('CloseHandle'))
406
+ assert_false(@singleton_methods.include?('ControlService'))
407
+ assert_false(@singleton_methods.include?('DeleteService'))
408
+ end
409
+
410
+ test "internal ffi functions are not public as instance methods" do
411
+ assert_false(@instance_methods.include?('CloseHandle'))
412
+ assert_false(@instance_methods.include?('ControlService'))
413
+ assert_false(@instance_methods.include?('DeleteService'))
414
+ end
415
+
416
+ def teardown
417
+ @display_name = nil
418
+ @service_name = nil
419
+ @service_stat = nil
420
+ @services = nil
421
+ end
422
+
423
+ def self.shutdown
424
+ @@host = nil
425
+ status = Win32::Service.status(@@service_name).current_state
426
+
427
+ if status == 'paused'
428
+ Win32::Service.resume(@@service_name)
429
+ end
430
+
431
+ unless ['running', 'start pending'].include?(status)
432
+ Win32::Service.start(@@service_name)
433
+ end
434
+
435
+ @@elevated = nil
436
+ end
437
+ end