win32-service 0.7.2 → 0.8.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.
- data/CHANGES +4 -0
- data/MANIFEST +2 -3
- data/README +75 -71
- data/Rakefile +7 -90
- data/doc/daemon.txt +7 -7
- data/doc/service.txt +8 -9
- data/examples/demo_daemon.rb +11 -11
- data/examples/demo_daemon_ctl.rb +3 -3
- data/examples/demo_services.rb +30 -30
- data/lib/win32/daemon.rb +345 -0
- data/lib/win32/service.rb +346 -434
- data/lib/win32/windows/constants.rb +137 -0
- data/lib/win32/windows/functions.rb +63 -0
- data/lib/win32/windows/helper.rb +41 -0
- data/lib/win32/windows/structs.rb +96 -0
- data/test/test_win32_daemon.rb +10 -13
- data/test/test_win32_service.rb +54 -48
- data/test/test_win32_service_configure.rb +19 -22
- data/test/test_win32_service_create.rb +129 -131
- data/test/test_win32_service_info.rb +8 -9
- data/test/test_win32_service_status.rb +2 -5
- data/win32-service.gemspec +5 -11
- metadata +61 -74
- data/ext/extconf.rb +0 -9
- data/ext/win32/daemon.c +0 -612
@@ -0,0 +1,137 @@
|
|
1
|
+
module Windows
|
2
|
+
module Constants
|
3
|
+
SC_MANAGER_ALL_ACCESS = 0xF003F
|
4
|
+
SC_MANAGER_CREATE_SERVICE = 0x0002
|
5
|
+
SC_MANAGER_CONNECT = 0x0001
|
6
|
+
SC_MANAGER_ENUMERATE_SERVICE = 0x0004
|
7
|
+
SC_MANAGER_LOCK = 0x0008
|
8
|
+
SC_MANAGER_MODIFY_BOOT_CONFIG = 0x0020
|
9
|
+
SC_MANAGER_QUERY_LOCK_STATUS = 0x0010
|
10
|
+
SC_STATUS_PROCESS_INFO = 0
|
11
|
+
SC_ENUM_PROCESS_INFO = 0
|
12
|
+
|
13
|
+
# Service control action types
|
14
|
+
SC_ACTION_NONE = 0
|
15
|
+
SC_ACTION_RESTART = 1
|
16
|
+
SC_ACTION_REBOOT = 2
|
17
|
+
SC_ACTION_RUN_COMMAND = 3
|
18
|
+
|
19
|
+
# Service access rights
|
20
|
+
SERVICE_ALL_ACCESS = 0xF01FF
|
21
|
+
SERVICE_CHANGE_CONFIG = 0x0002
|
22
|
+
SERVICE_ENUMERATE_DEPENDENTS = 0x0008
|
23
|
+
SERVICE_INTERROGATE = 0x0080
|
24
|
+
SERVICE_PAUSE_CONTINUE = 0x0040
|
25
|
+
SERVICE_QUERY_CONFIG = 0x0001
|
26
|
+
SERVICE_QUERY_STATUS = 0x0004
|
27
|
+
SERVICE_START = 0x0010
|
28
|
+
SERVICE_STOP = 0x0020
|
29
|
+
SERVICE_USER_DEFINED_CONTROL = 0x0100
|
30
|
+
|
31
|
+
# Service types
|
32
|
+
SERVICE_KERNEL_DRIVER = 0x00000001
|
33
|
+
SERVICE_FILE_SYSTEM_DRIVER = 0x00000002
|
34
|
+
SERVICE_ADAPTER = 0x00000004
|
35
|
+
SERVICE_RECOGNIZER_DRIVER = 0x00000008
|
36
|
+
SERVICE_WIN32_OWN_PROCESS = 0x00000010
|
37
|
+
SERVICE_WIN32_SHARE_PROCESS = 0x00000020
|
38
|
+
SERVICE_WIN32 = 0x00000030
|
39
|
+
SERVICE_INTERACTIVE_PROCESS = 0x00000100
|
40
|
+
SERVICE_DRIVER = 0x0000000B
|
41
|
+
SERVICE_TYPE_ALL = 0x0000013F
|
42
|
+
|
43
|
+
# Error control
|
44
|
+
SERVICE_ERROR_IGNORE = 0x00000000
|
45
|
+
SERVICE_ERROR_NORMAL = 0x00000001
|
46
|
+
SERVICE_ERROR_SEVERE = 0x00000002
|
47
|
+
SERVICE_ERROR_CRITICAL = 0x00000003
|
48
|
+
|
49
|
+
# Start types
|
50
|
+
SERVICE_BOOT_START = 0x00000000
|
51
|
+
SERVICE_SYSTEM_START = 0x00000001
|
52
|
+
SERVICE_AUTO_START = 0x00000002
|
53
|
+
SERVICE_DEMAND_START = 0x00000003
|
54
|
+
SERVICE_DISABLED = 0x00000004
|
55
|
+
|
56
|
+
# Service control
|
57
|
+
|
58
|
+
SERVICE_CONTROL_STOP = 0x00000001
|
59
|
+
SERVICE_CONTROL_PAUSE = 0x00000002
|
60
|
+
SERVICE_CONTROL_CONTINUE = 0x00000003
|
61
|
+
SERVICE_CONTROL_INTERROGATE = 0x00000004
|
62
|
+
SERVICE_CONTROL_SHUTDOWN = 0x00000005
|
63
|
+
SERVICE_CONTROL_PARAMCHANGE = 0x00000006
|
64
|
+
SERVICE_CONTROL_NETBINDADD = 0x00000007
|
65
|
+
SERVICE_CONTROL_NETBINDREMOVE = 0x00000008
|
66
|
+
SERVICE_CONTROL_NETBINDENABLE = 0x00000009
|
67
|
+
SERVICE_CONTROL_NETBINDDISABLE = 0x0000000A
|
68
|
+
SERVICE_CONTROL_DEVICEEVENT = 0x0000000B
|
69
|
+
SERVICE_CONTROL_HARDWAREPROFILECHANGE = 0x0000000C
|
70
|
+
SERVICE_CONTROL_POWEREVENT = 0x0000000D
|
71
|
+
SERVICE_CONTROL_SESSIONCHANGE = 0x0000000E
|
72
|
+
SERVICE_CONTROL_PRESHUTDOWN = 0x0000000F
|
73
|
+
SERVICE_CONTROL_TIMECHANGE = 0x00000010
|
74
|
+
SERVICE_CONTROL_TRIGGEREVENT = 0x00000020
|
75
|
+
|
76
|
+
# Service controls accepted
|
77
|
+
|
78
|
+
SERVICE_ACCEPT_STOP = 0x00000001
|
79
|
+
SERVICE_ACCEPT_PAUSE_CONTINUE = 0x00000002
|
80
|
+
SERVICE_ACCEPT_SHUTDOWN = 0x00000004
|
81
|
+
SERVICE_ACCEPT_PARAMCHANGE = 0x00000008
|
82
|
+
SERVICE_ACCEPT_NETBINDCHANGE = 0x00000010
|
83
|
+
SERVICE_ACCEPT_HARDWAREPROFILECHANGE = 0x00000020
|
84
|
+
SERVICE_ACCEPT_POWEREVENT = 0x00000040
|
85
|
+
SERVICE_ACCEPT_SESSIONCHANGE = 0x00000080
|
86
|
+
SERVICE_ACCEPT_PRESHUTDOWN = 0x00000100
|
87
|
+
SERVICE_ACCEPT_TIMECHANGE = 0x00000200
|
88
|
+
SERVICE_ACCEPT_TRIGGEREVENT = 0x00000400
|
89
|
+
|
90
|
+
# Service states
|
91
|
+
SERVICE_ACTIVE = 0x00000001
|
92
|
+
SERVICE_INACTIVE = 0x00000002
|
93
|
+
SERVICE_STATE_ALL = 0x00000003
|
94
|
+
|
95
|
+
# Service current states
|
96
|
+
SERVICE_STOPPED = 0x00000001
|
97
|
+
SERVICE_START_PENDING = 0x00000002
|
98
|
+
SERVICE_STOP_PENDING = 0x00000003
|
99
|
+
SERVICE_RUNNING = 0x00000004
|
100
|
+
SERVICE_CONTINUE_PENDING = 0x00000005
|
101
|
+
SERVICE_PAUSE_PENDING = 0x00000006
|
102
|
+
SERVICE_PAUSED = 0x00000007
|
103
|
+
|
104
|
+
# Info levels
|
105
|
+
SERVICE_CONFIG_DESCRIPTION = 1
|
106
|
+
SERVICE_CONFIG_FAILURE_ACTIONS = 2
|
107
|
+
SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 3
|
108
|
+
SERVICE_CONFIG_FAILURE_ACTIONS_FLAG = 4
|
109
|
+
SERVICE_CONFIG_SERVICE_SID_INFO = 5
|
110
|
+
SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO = 6
|
111
|
+
SERVICE_CONFIG_PRESHUTDOWN_INFO = 7
|
112
|
+
|
113
|
+
# Configuration
|
114
|
+
SERVICE_NO_CHANGE = 0xffffffff
|
115
|
+
|
116
|
+
# Misc
|
117
|
+
|
118
|
+
WAIT_OBJECT_0 = 0
|
119
|
+
WAIT_TIMEOUT = 0x00000102
|
120
|
+
INFINITE = 0xFFFFFFFF
|
121
|
+
|
122
|
+
IDLE_CONTROL_CODE = 0
|
123
|
+
|
124
|
+
DELETE = 0x00010000
|
125
|
+
FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
|
126
|
+
FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200
|
127
|
+
|
128
|
+
NO_ERROR = 0
|
129
|
+
|
130
|
+
# Errors
|
131
|
+
|
132
|
+
ERROR_INSUFFICIENT_BUFFER = 122
|
133
|
+
ERROR_MORE_DATA = 234
|
134
|
+
ERROR_FILE_NOT_FOUND = 2
|
135
|
+
WAIT_FAILED = 0xFFFFFFFF
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module Windows
|
4
|
+
module Functions
|
5
|
+
extend FFI::Library
|
6
|
+
|
7
|
+
typedef :ulong, :dword
|
8
|
+
typedef :uintptr_t, :handle
|
9
|
+
typedef :pointer, :ptr
|
10
|
+
typedef :string, :str
|
11
|
+
|
12
|
+
ffi_convention :stdcall
|
13
|
+
|
14
|
+
ffi_lib :kernel32
|
15
|
+
|
16
|
+
attach_function :CloseHandle, [:handle], :bool
|
17
|
+
attach_function :CreateEvent, :CreateEventA, [:ptr, :bool, :bool, :str], :handle
|
18
|
+
attach_function :CreateThread, [:ptr, :size_t, :ptr, :ptr, :dword, :ptr], :handle, :blocking => true
|
19
|
+
attach_function :EnterCriticalSection, [:ptr], :void
|
20
|
+
attach_function :FormatMessage, :FormatMessageA, [:ulong, :ptr, :ulong, :ulong, :str, :ulong, :ptr], :ulong
|
21
|
+
attach_function :InitializeCriticalSection, [:ptr], :void
|
22
|
+
attach_function :LeaveCriticalSection, [:ptr], :void
|
23
|
+
attach_function :SetEvent, [:handle], :bool
|
24
|
+
attach_function :WaitForSingleObject, [:handle, :dword], :dword, :blocking => true
|
25
|
+
attach_function :WaitForMultipleObjects, [:dword, :ptr, :bool, :dword], :dword
|
26
|
+
|
27
|
+
ffi_lib :advapi32
|
28
|
+
|
29
|
+
callback :handler_ex, [:ulong, :ulong, :ptr, :ptr], :void
|
30
|
+
|
31
|
+
attach_function :CloseServiceHandle, [:handle], :bool
|
32
|
+
|
33
|
+
attach_function :ChangeServiceConfig, :ChangeServiceConfigA,
|
34
|
+
[:handle, :dword, :dword, :dword, :str, :str, :ptr, :str, :str, :str, :str],
|
35
|
+
:bool
|
36
|
+
|
37
|
+
attach_function :ChangeServiceConfig2, :ChangeServiceConfig2A, [:handle, :dword, :ptr], :bool
|
38
|
+
|
39
|
+
attach_function :CreateService, :CreateServiceA,
|
40
|
+
[:handle, :string, :string, :dword, :dword, :dword, :dword,
|
41
|
+
:string, :string, :ptr, :pointer, :string, :string],
|
42
|
+
:handle
|
43
|
+
|
44
|
+
attach_function :ControlService, [:handle, :dword, :ptr], :bool
|
45
|
+
attach_function :DeleteService, [:handle], :bool
|
46
|
+
|
47
|
+
attach_function :EnumServicesStatusEx, :EnumServicesStatusExA,
|
48
|
+
[:handle, :int, :dword, :dword, :ptr, :dword, :ptr, :ptr, :ptr, :string],
|
49
|
+
:bool
|
50
|
+
|
51
|
+
attach_function :GetServiceDisplayName, :GetServiceDisplayNameA, [:handle, :string, :ptr, :ptr], :bool
|
52
|
+
attach_function :GetServiceKeyName, :GetServiceKeyNameA, [:handle, :string, :ptr, :ptr], :bool
|
53
|
+
attach_function :OpenSCManager, :OpenSCManagerA, [:ptr, :ptr, :dword], :handle
|
54
|
+
attach_function :OpenService, :OpenServiceA, [:handle, :string, :dword], :handle
|
55
|
+
attach_function :QueryServiceConfig, :QueryServiceConfigA, [:handle, :ptr, :dword, :ptr], :bool
|
56
|
+
attach_function :QueryServiceConfig2, :QueryServiceConfig2A, [:handle, :dword, :ptr, :dword, :ptr], :bool
|
57
|
+
attach_function :QueryServiceStatusEx, [:handle, :int, :ptr, :dword, :ptr], :bool
|
58
|
+
attach_function :RegisterServiceCtrlHandlerEx, :RegisterServiceCtrlHandlerExA, [:str, :handler_ex, :ptr], :handle
|
59
|
+
attach_function :SetServiceStatus, [:handle, :ptr], :bool
|
60
|
+
attach_function :StartService, :StartServiceA, [:handle, :dword, :ptr], :bool
|
61
|
+
attach_function :StartServiceCtrlDispatcher, :StartServiceCtrlDispatcherA, [:ptr], :bool, :blocking => true
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
class FFI::Pointer
|
4
|
+
def read_array_of_null_separated_strings
|
5
|
+
elements = []
|
6
|
+
loc = self
|
7
|
+
|
8
|
+
while element = loc.read_string
|
9
|
+
break if element.nil? || element == ""
|
10
|
+
elements << element
|
11
|
+
loc += element.size + 1
|
12
|
+
end
|
13
|
+
|
14
|
+
elements
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module FFI
|
19
|
+
extend FFI::Library
|
20
|
+
|
21
|
+
ffi_lib :kernel32
|
22
|
+
|
23
|
+
attach_function :FormatMessage, :FormatMessageA,
|
24
|
+
[:ulong, :pointer, :ulong, :ulong, :pointer, :ulong, :pointer], :ulong
|
25
|
+
|
26
|
+
def win_error(function, err=FFI.errno)
|
27
|
+
flags = 0x00001000 | 0x00000200
|
28
|
+
buf = FFI::MemoryPointer.new(:char, 1024)
|
29
|
+
|
30
|
+
FormatMessage(flags, nil, err , 0x0409, buf, 1024, nil)
|
31
|
+
|
32
|
+
function + ': ' + buf.read_string.strip
|
33
|
+
end
|
34
|
+
|
35
|
+
def raise_windows_error(function, err=FFI.errno)
|
36
|
+
raise SystemCallError.new(win_error(function, err), err)
|
37
|
+
end
|
38
|
+
|
39
|
+
module_function :win_error
|
40
|
+
module_function :raise_windows_error
|
41
|
+
end
|
@@ -0,0 +1,96 @@
|
|
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 QUERY_SERVICE_CONFIG < FFI::Struct
|
40
|
+
layout(
|
41
|
+
:dwServiceType, :dword,
|
42
|
+
:dwStartType, :dword,
|
43
|
+
:dwErrorControl, :dword,
|
44
|
+
:lpBinaryPathName, :pointer,
|
45
|
+
:lpLoadOrderGroup, :pointer,
|
46
|
+
:dwTagId, :dword,
|
47
|
+
:lpDependencies, :pointer,
|
48
|
+
:lpServiceStartName, :pointer,
|
49
|
+
:lpDisplayName, :pointer
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
class SERVICE_STATUS_PROCESS < FFI::Struct
|
54
|
+
layout(
|
55
|
+
:dwServiceType, :dword,
|
56
|
+
:dwCurrentState, :dword,
|
57
|
+
:dwControlsAccepted, :dword,
|
58
|
+
:dwWin32ExitCode, :dword,
|
59
|
+
:dwServiceSpecificExitCode, :dword,
|
60
|
+
:dwCheckPoint, :dword,
|
61
|
+
:dwWaitHint, :dword,
|
62
|
+
:dwProcessId, :dword,
|
63
|
+
:dwServiceFlags, :dword
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
class ENUM_SERVICE_STATUS_PROCESS < FFI::Struct
|
68
|
+
layout(
|
69
|
+
:lpServiceName, :pointer,
|
70
|
+
:lpDisplayName, :pointer,
|
71
|
+
:ServiceStatusProcess, SERVICE_STATUS_PROCESS
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
class SC_ACTION < FFI::Struct
|
76
|
+
layout(:Type, :int, :Delay, :dword)
|
77
|
+
end
|
78
|
+
|
79
|
+
class SERVICE_FAILURE_ACTIONS < FFI::Struct
|
80
|
+
layout(
|
81
|
+
:dwResetPeriod, :dword,
|
82
|
+
:lpRebootMsg, :pointer,
|
83
|
+
:lpCommand, :pointer,
|
84
|
+
:cActions, :dword,
|
85
|
+
:lpsaActions, :pointer # Array of SC_ACTION structs
|
86
|
+
)
|
87
|
+
end
|
88
|
+
|
89
|
+
class SERVICE_TABLE_ENTRY < FFI::Struct
|
90
|
+
layout(
|
91
|
+
:lpServiceName, :pointer,
|
92
|
+
:lpServiceProc, :pointer
|
93
|
+
)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/test/test_win32_daemon.rb
CHANGED
@@ -7,22 +7,19 @@
|
|
7
7
|
# These tests are rather limited, since the acid test is to install
|
8
8
|
# your daemon as a service and see how it behaves.
|
9
9
|
#########################################################################
|
10
|
-
require '
|
11
|
-
gem 'test-unit'
|
12
|
-
|
10
|
+
require 'test-unit'
|
13
11
|
require 'win32/daemon'
|
14
|
-
require 'test/unit'
|
15
12
|
include Win32
|
16
13
|
|
17
14
|
class TC_Daemon < Test::Unit::TestCase
|
18
15
|
def setup
|
19
16
|
@daemon = Daemon.new
|
20
17
|
end
|
21
|
-
|
18
|
+
|
22
19
|
test "version number is set properly" do
|
23
|
-
assert_equal('0.
|
20
|
+
assert_equal('0.8.0', Daemon::VERSION)
|
24
21
|
end
|
25
|
-
|
22
|
+
|
26
23
|
test "constructor basic functionality" do
|
27
24
|
assert_respond_to(Daemon, :new)
|
28
25
|
assert_nothing_raised{ Daemon.new }
|
@@ -31,19 +28,19 @@ class TC_Daemon < Test::Unit::TestCase
|
|
31
28
|
test "constructor does not accept any arguments" do
|
32
29
|
assert_raises(ArgumentError){ Daemon.new(1) }
|
33
30
|
end
|
34
|
-
|
31
|
+
|
35
32
|
test "mainloop basic functionality" do
|
36
33
|
assert_respond_to(@daemon, :mainloop)
|
37
34
|
end
|
38
|
-
|
35
|
+
|
39
36
|
test "state basic functionality" do
|
40
37
|
assert_respond_to(@daemon, :state)
|
41
38
|
end
|
42
|
-
|
39
|
+
|
43
40
|
test "is_running basic functionality" do
|
44
41
|
assert_respond_to(@daemon, :running?)
|
45
42
|
end
|
46
|
-
|
43
|
+
|
47
44
|
test "expected constants are defined" do
|
48
45
|
assert_not_nil(Daemon::CONTINUE_PENDING)
|
49
46
|
assert_not_nil(Daemon::PAUSE_PENDING)
|
@@ -52,9 +49,9 @@ class TC_Daemon < Test::Unit::TestCase
|
|
52
49
|
assert_not_nil(Daemon::START_PENDING)
|
53
50
|
assert_not_nil(Daemon::STOP_PENDING)
|
54
51
|
assert_not_nil(Daemon::STOPPED)
|
55
|
-
assert_not_nil(Daemon::IDLE)
|
52
|
+
assert_not_nil(Daemon::IDLE)
|
56
53
|
end
|
57
|
-
|
54
|
+
|
58
55
|
def teardown
|
59
56
|
@daemon = nil
|
60
57
|
end
|
data/test/test_win32_service.rb
CHANGED
@@ -1,14 +1,12 @@
|
|
1
1
|
##########################################################################
|
2
2
|
# test_win32_service.rb
|
3
|
-
#
|
3
|
+
#
|
4
4
|
# Tests for the Win32::Service class.
|
5
5
|
##########################################################################
|
6
|
-
require '
|
7
|
-
gem 'test-unit'
|
8
|
-
|
6
|
+
require 'test-unit'
|
9
7
|
require 'win32/service'
|
8
|
+
require 'win32/security'
|
10
9
|
require 'socket'
|
11
|
-
require 'test/unit'
|
12
10
|
|
13
11
|
class TC_Win32_Service < Test::Unit::TestCase
|
14
12
|
def self.startup
|
@@ -21,6 +19,7 @@ class TC_Win32_Service < Test::Unit::TestCase
|
|
21
19
|
@service_name = 'stisvc'
|
22
20
|
@service_stat = nil
|
23
21
|
@services = []
|
22
|
+
@elevated = Win32::Security.elevated_security?
|
24
23
|
end
|
25
24
|
|
26
25
|
def start_service(service)
|
@@ -42,7 +41,7 @@ class TC_Win32_Service < Test::Unit::TestCase
|
|
42
41
|
end
|
43
42
|
wait_for_status('stopped')
|
44
43
|
end
|
45
|
-
|
44
|
+
|
46
45
|
# Helper method that waits for a status to change its state since state
|
47
46
|
# changes aren't usually instantaneous.
|
48
47
|
def wait_for_status(status)
|
@@ -50,28 +49,28 @@ class TC_Win32_Service < Test::Unit::TestCase
|
|
50
49
|
end
|
51
50
|
|
52
51
|
test "version number is expected value" do
|
53
|
-
assert_equal('0.
|
52
|
+
assert_equal('0.8.0', Win32::Service::VERSION)
|
54
53
|
end
|
55
|
-
|
54
|
+
|
56
55
|
test "services basic functionality" do
|
57
56
|
assert_respond_to(Win32::Service, :services)
|
58
57
|
assert_nothing_raised{ Win32::Service.services }
|
59
58
|
assert_nothing_raised{ Win32::Service.services(nil) }
|
60
59
|
assert_nothing_raised{ Win32::Service.services(nil, 'network') }
|
61
60
|
end
|
62
|
-
|
61
|
+
|
63
62
|
test "services method returns an array without a block" do
|
64
63
|
assert_nothing_raised{ @services = Win32::Service.services }
|
65
64
|
assert_kind_of(Array, @services)
|
66
65
|
assert_kind_of(Struct::ServiceInfo, @services[0])
|
67
66
|
end
|
68
|
-
|
67
|
+
|
69
68
|
test "services method yields service objects when a block is provided" do
|
70
69
|
assert_nothing_raised{ Win32::Service.services{ |s| @services << s } }
|
71
70
|
assert_kind_of(Array, @services)
|
72
|
-
assert_kind_of(Struct::ServiceInfo, @services[0])
|
71
|
+
assert_kind_of(Struct::ServiceInfo, @services[0])
|
73
72
|
end
|
74
|
-
|
73
|
+
|
75
74
|
test "the host argument must be a string or an error is raised" do
|
76
75
|
assert_raise(TypeError){ Win32::Service.services(1) }
|
77
76
|
end
|
@@ -85,29 +84,29 @@ class TC_Win32_Service < Test::Unit::TestCase
|
|
85
84
|
end
|
86
85
|
|
87
86
|
test "a valid hostname must be provided or an error is raised" do
|
88
|
-
assert_raise(
|
89
|
-
end
|
90
|
-
|
87
|
+
assert_raise(SystemCallError){ Win32::Service.services('bogus') }
|
88
|
+
end
|
89
|
+
|
91
90
|
test "delete method basic functionality" do
|
92
91
|
assert_respond_to(Win32::Service, :delete)
|
93
92
|
end
|
94
|
-
|
93
|
+
|
95
94
|
test "a service name must be provided to the delete method" do
|
96
95
|
assert_raise(ArgumentError){ Win32::Service.delete }
|
97
96
|
end
|
98
97
|
|
99
98
|
test "delete method raises an error if a bogus service name is provided" do
|
100
|
-
assert_raise(
|
99
|
+
assert_raise(SystemCallError){ Win32::Service.delete('bogus') }
|
101
100
|
end
|
102
101
|
|
103
102
|
test "delete method raises an error if a bogus host name is provided" do
|
104
|
-
assert_raise(
|
103
|
+
assert_raise(SystemCallError){ Win32::Service.delete('bogus', 'bogus') }
|
105
104
|
end
|
106
105
|
|
107
106
|
test "delete method only accepts up to two arguments" do
|
108
107
|
assert_raise(ArgumentError){ Win32::Service.delete('x', 'y', 'z') }
|
109
108
|
end
|
110
|
-
|
109
|
+
|
111
110
|
test "pause basic functionality" do
|
112
111
|
assert_respond_to(Win32::Service, :pause)
|
113
112
|
end
|
@@ -117,6 +116,7 @@ class TC_Win32_Service < Test::Unit::TestCase
|
|
117
116
|
end
|
118
117
|
|
119
118
|
test "pause and resume work as expected" do
|
119
|
+
omit_unless(@elevated, "Skipped unless run with admin privileges")
|
120
120
|
start_service(@service_name)
|
121
121
|
|
122
122
|
assert_nothing_raised{ Win32::Service.pause(@service_name) }
|
@@ -129,47 +129,47 @@ class TC_Win32_Service < Test::Unit::TestCase
|
|
129
129
|
test "pausing an already paused service is harmless" do
|
130
130
|
start_service(@service_name)
|
131
131
|
|
132
|
-
assert_nothing_raised{ Win32::Service.pause(@service_name) }
|
132
|
+
assert_nothing_raised{ Win32::Service.pause(@service_name) }
|
133
133
|
wait_for_status('paused')
|
134
|
-
assert_nothing_raised{ Win32::Service.pause(@service_name) }
|
134
|
+
assert_nothing_raised{ Win32::Service.pause(@service_name) }
|
135
135
|
end
|
136
|
-
|
136
|
+
|
137
137
|
test "pause requires a service name as an argument" do
|
138
138
|
assert_raise(ArgumentError){ Win32::Service.pause }
|
139
139
|
end
|
140
140
|
|
141
141
|
test "pausing an unrecognized service name raises an error" do
|
142
|
-
assert_raise(
|
142
|
+
assert_raise(SystemCallError){ Win32::Service.pause('bogus') }
|
143
143
|
end
|
144
144
|
|
145
145
|
test "pausing a service on an unrecognized host raises an error" do
|
146
|
-
assert_raise(
|
146
|
+
assert_raise(SystemCallError){ Win32::Service.pause('W32Time', 'bogus') }
|
147
147
|
end
|
148
148
|
|
149
149
|
test "pause method accepts a maximum of two arguments" do
|
150
150
|
assert_raise(ArgumentError){ Win32::Service.pause('x', 'y', 'z') }
|
151
151
|
end
|
152
|
-
|
152
|
+
|
153
153
|
test "resume method requires a service name" do
|
154
154
|
assert_raise(ArgumentError){ Win32::Service.resume }
|
155
155
|
end
|
156
156
|
|
157
157
|
test "resume method with an unrecognized service name raises an error" do
|
158
|
-
assert_raise(
|
158
|
+
assert_raise(SystemCallError){ Win32::Service.resume('bogus') }
|
159
159
|
end
|
160
160
|
|
161
161
|
test "resume method with an unrecognized host name raises an error" do
|
162
|
-
assert_raise(
|
162
|
+
assert_raise(SystemCallError){ Win32::Service.resume('W32Time', 'bogus') }
|
163
163
|
end
|
164
164
|
|
165
165
|
test "resume method accepts a maximum of two arguments" do
|
166
166
|
assert_raise(ArgumentError){ Win32::Service.resume('W32Time', @@host, true) }
|
167
|
-
end
|
167
|
+
end
|
168
168
|
|
169
169
|
test "stop method basic functionality" do
|
170
170
|
assert_respond_to(Win32::Service, :stop)
|
171
171
|
end
|
172
|
-
|
172
|
+
|
173
173
|
test "start method basic functionality" do
|
174
174
|
assert_respond_to(Win32::Service, :start)
|
175
175
|
end
|
@@ -189,41 +189,41 @@ class TC_Win32_Service < Test::Unit::TestCase
|
|
189
189
|
|
190
190
|
assert_nothing_raised{ Win32::Service.stop(@service_name) }
|
191
191
|
wait_for_status('stopped')
|
192
|
-
assert_raise(
|
192
|
+
assert_raise(SystemCallError){ Win32::Service.stop(@service_name) }
|
193
193
|
|
194
194
|
assert_nothing_raised{ Win32::Service.start(@service_name) }
|
195
195
|
end
|
196
|
-
|
196
|
+
|
197
197
|
test "stop method requires a service name" do
|
198
198
|
assert_raise(ArgumentError){ Win32::Service.stop }
|
199
199
|
end
|
200
200
|
|
201
201
|
test "stop method raises an error if the service name is unrecognized" do
|
202
|
-
assert_raise(
|
202
|
+
assert_raise(SystemCallError){ Win32::Service.stop('bogus') }
|
203
203
|
end
|
204
204
|
|
205
205
|
test "stop method raises an error if the host is unrecognized" do
|
206
|
-
assert_raise(
|
206
|
+
assert_raise(SystemCallError){ Win32::Service.stop('W32Time', 'bogus') }
|
207
207
|
end
|
208
208
|
|
209
209
|
test "stop metho accepts a maximum of two arguments" do
|
210
210
|
assert_raise(ArgumentError){ Win32::Service.stop('W32Time', @@host, true) }
|
211
211
|
end
|
212
|
-
|
212
|
+
|
213
213
|
test "start method requires a service name" do
|
214
214
|
assert_raise(ArgumentError){ Win32::Service.start }
|
215
215
|
end
|
216
216
|
|
217
217
|
test "attempting to start a running service raises an error" do
|
218
|
-
assert_raise(
|
218
|
+
assert_raise(SystemCallError){ Win32::Service.start(@service_name) }
|
219
219
|
end
|
220
220
|
|
221
221
|
test "attempting to start an unrecognized service raises an error" do
|
222
|
-
assert_raise(
|
222
|
+
assert_raise(SystemCallError){ Win32::Service.start('bogus') }
|
223
223
|
end
|
224
224
|
|
225
225
|
test "attempting to start a service on an unknown host raises an error" do
|
226
|
-
assert_raise(
|
226
|
+
assert_raise(SystemCallError){ Win32::Service.start('bogus', 'bogus') }
|
227
227
|
end
|
228
228
|
|
229
229
|
test "stop requires at least one argument" do
|
@@ -231,11 +231,11 @@ class TC_Win32_Service < Test::Unit::TestCase
|
|
231
231
|
end
|
232
232
|
|
233
233
|
test "stop raises an error with an unrecognized service name" do
|
234
|
-
assert_raise(
|
234
|
+
assert_raise(SystemCallError){ Win32::Service.stop('bogus') }
|
235
235
|
end
|
236
236
|
|
237
237
|
test "stop raises an error with an unrecognized host" do
|
238
|
-
assert_raise(
|
238
|
+
assert_raise(SystemCallError){ Win32::Service.stop('W32Time', 'bogus') }
|
239
239
|
end
|
240
240
|
|
241
241
|
test "stop accepts a maximum of 2 arguments" do
|
@@ -268,11 +268,11 @@ class TC_Win32_Service < Test::Unit::TestCase
|
|
268
268
|
end
|
269
269
|
|
270
270
|
test "get_service_name raises an error if a bogus service name is provided" do
|
271
|
-
assert_raise(
|
271
|
+
assert_raise(SystemCallError){ Win32::Service.get_service_name('bogus') }
|
272
272
|
end
|
273
273
|
|
274
274
|
test "get_service_name raises an error if a bogus host is provided" do
|
275
|
-
assert_raise(
|
275
|
+
assert_raise(SystemCallError){ Win32::Service.get_service_name('foo', 'bogus') }
|
276
276
|
end
|
277
277
|
|
278
278
|
test "get_service_name accepts a maximum of two arguments" do
|
@@ -299,11 +299,11 @@ class TC_Win32_Service < Test::Unit::TestCase
|
|
299
299
|
end
|
300
300
|
|
301
301
|
test "get_display_name raises an error if the service does not exist" do
|
302
|
-
assert_raise(
|
302
|
+
assert_raise(SystemCallError){ Win32::Service.get_display_name('bogus') }
|
303
303
|
end
|
304
304
|
|
305
305
|
test "get_display_name raises an error if a bad host name is provided" do
|
306
|
-
assert_raise(
|
306
|
+
assert_raise(SystemCallError){ Win32::Service.get_display_name('W32Time', 'bogus') }
|
307
307
|
end
|
308
308
|
|
309
309
|
test "get_display_name takes a maximum of two arguments" do
|
@@ -312,6 +312,7 @@ class TC_Win32_Service < Test::Unit::TestCase
|
|
312
312
|
|
313
313
|
test "exists method basic functionality" do
|
314
314
|
assert_respond_to(Win32::Service, :exists?)
|
315
|
+
assert_boolean(Win32::Service.exists?('W32Time'))
|
315
316
|
assert_nothing_raised{ Win32::Service.exists?('W32Time') }
|
316
317
|
end
|
317
318
|
|
@@ -325,13 +326,17 @@ class TC_Win32_Service < Test::Unit::TestCase
|
|
325
326
|
end
|
326
327
|
|
327
328
|
test "exists method raises an error if a bogus host is passed" do
|
328
|
-
assert_raises(
|
329
|
+
assert_raises(SystemCallError){
|
330
|
+
Win32::Service.exists?('foo', 'bogushost')
|
331
|
+
}
|
329
332
|
end
|
330
333
|
|
331
334
|
test "exists method only accepts up to two arguments" do
|
332
|
-
assert_raises(ArgumentError){
|
335
|
+
assert_raises(ArgumentError){
|
336
|
+
Win32::Service.exists?('foo', 'bar', 'baz')
|
337
|
+
}
|
333
338
|
end
|
334
|
-
|
339
|
+
|
335
340
|
test "scm security constants are defined" do
|
336
341
|
assert_not_nil(Win32::Service::MANAGER_ALL_ACCESS)
|
337
342
|
assert_not_nil(Win32::Service::MANAGER_CREATE_SERVICE)
|
@@ -384,14 +389,15 @@ class TC_Win32_Service < Test::Unit::TestCase
|
|
384
389
|
assert_not_nil(Win32::Service::RUNNING)
|
385
390
|
assert_not_nil(Win32::Service::START_PENDING)
|
386
391
|
assert_not_nil(Win32::Service::STOP_PENDING)
|
387
|
-
assert_not_nil(Win32::Service::STOPPED)
|
392
|
+
assert_not_nil(Win32::Service::STOPPED)
|
388
393
|
end
|
389
|
-
|
394
|
+
|
390
395
|
def teardown
|
391
396
|
@display_name = nil
|
392
397
|
@service_name = nil
|
393
398
|
@service_stat = nil
|
394
399
|
@services = nil
|
400
|
+
@elevated = nil
|
395
401
|
end
|
396
402
|
|
397
403
|
def self.shutdown
|