win32-service 0.8.6 → 0.8.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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