win32-service 1.0.1 → 2.1.2
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.
- checksums.yaml +4 -4
- data/lib/win32/daemon.rb +2 -1
- data/lib/win32/service.rb +145 -36
- data/lib/win32/windows/version.rb +1 -1
- metadata +50 -39
- data/CHANGELOG.md +0 -347
- data/Gemfile +0 -5
- data/MANIFEST +0 -24
- data/README.md +0 -75
- data/Rakefile +0 -83
- data/VERSION +0 -1
- data/appveyor.yml +0 -48
- data/doc/daemon.txt +0 -157
- data/doc/service.txt +0 -363
- data/examples/demo_daemon.rb +0 -96
- data/examples/demo_daemon_ctl.rb +0 -123
- data/examples/demo_services.rb +0 -30
- data/test/test_win32_daemon.rb +0 -58
- data/test/test_win32_service.rb +0 -468
- data/test/test_win32_service_configure.rb +0 -110
- data/test/test_win32_service_create.rb +0 -153
- data/test/test_win32_service_info.rb +0 -189
- data/test/test_win32_service_status.rb +0 -110
- data/win32-service.gemspec +0 -41
data/examples/demo_daemon.rb
DELETED
@@ -1,96 +0,0 @@
|
|
1
|
-
LOG_FILE = 'C:\\Tmp\\win32_daemon_test.log'
|
2
|
-
|
3
|
-
begin
|
4
|
-
require 'rubygems'
|
5
|
-
require 'win32/daemon'
|
6
|
-
include Win32
|
7
|
-
|
8
|
-
class DemoDaemon < Daemon
|
9
|
-
# This method fires off before the +service_main+ mainloop is entered.
|
10
|
-
# Any pre-setup code you need to run before your service's mainloop
|
11
|
-
# starts should be put here. Otherwise the service might fail with a
|
12
|
-
# timeout error when you try to start it.
|
13
|
-
#
|
14
|
-
def service_init
|
15
|
-
Dir.mkdir("C:/Tmp") unless File.exist?("C:/Tmp")
|
16
|
-
10.times{ |i|
|
17
|
-
File.open(LOG_FILE , 'a'){ |f| f.puts("#{i}") }
|
18
|
-
sleep 1
|
19
|
-
}
|
20
|
-
end
|
21
|
-
|
22
|
-
# This is the daemon's mainloop. In other words, whatever runs here
|
23
|
-
# is the code that runs while your service is running. Note that the
|
24
|
-
# loop is not implicit.
|
25
|
-
#
|
26
|
-
# You must setup a loop as I've done here with the 'while running?'
|
27
|
-
# code, or setup your own loop. Otherwise your service will exit and
|
28
|
-
# won't be especially useful.
|
29
|
-
#
|
30
|
-
# In this particular case, I've setup a loop to append a short message
|
31
|
-
# and timestamp to a file on your C: drive every 20 seconds. Be sure
|
32
|
-
# to stop the service when you're done!
|
33
|
-
#
|
34
|
-
def service_main(*args)
|
35
|
-
msg = 'service_main entered at: ' + Time.now.to_s
|
36
|
-
|
37
|
-
File.open(LOG_FILE, 'a'){ |f|
|
38
|
-
f.puts msg
|
39
|
-
f.puts "Args: " + args.join(',')
|
40
|
-
}
|
41
|
-
|
42
|
-
# While we're in here the daemon is running.
|
43
|
-
while running?
|
44
|
-
if state == RUNNING
|
45
|
-
sleep 20
|
46
|
-
msg = 'Service is running as of: ' + Time.now.to_s
|
47
|
-
File.open(LOG_FILE, 'a'){ |f| f.puts msg }
|
48
|
-
else # PAUSED or IDLE
|
49
|
-
sleep 0.5
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
# We've left the loop, the daemon is about to exit.
|
54
|
-
|
55
|
-
File.open(LOG_FILE, 'a'){ |f| f.puts "STATE: #{state}" }
|
56
|
-
|
57
|
-
msg = 'service_main left at: ' + Time.now.to_s
|
58
|
-
|
59
|
-
File.open(LOG_FILE, 'a'){ |f| f.puts msg }
|
60
|
-
end
|
61
|
-
|
62
|
-
# This event triggers when the service receives a signal to stop.
|
63
|
-
#
|
64
|
-
# NOTE: Older versions of this code used an explicit exit! call
|
65
|
-
# to force the Ruby interpreter to exit. Don't do that. It is no
|
66
|
-
# longer required and, in fact, may cause issues.
|
67
|
-
#
|
68
|
-
def service_stop
|
69
|
-
msg = 'Received stop signal at: ' + Time.now.to_s
|
70
|
-
File.open(LOG_FILE, 'a'){ |f| f.puts msg }
|
71
|
-
end
|
72
|
-
|
73
|
-
# This event triggers when the service receives a signal to pause.
|
74
|
-
#
|
75
|
-
def service_pause
|
76
|
-
msg = 'Received pause signal at: ' + Time.now.to_s
|
77
|
-
File.open(LOG_FILE, 'a'){ |f| f.puts msg }
|
78
|
-
end
|
79
|
-
|
80
|
-
# This event triggers when the service receives a signal to resume
|
81
|
-
# from a paused state.
|
82
|
-
#
|
83
|
-
def service_resume
|
84
|
-
msg = 'Received resume signal at: ' + Time.now.to_s
|
85
|
-
File.open(LOG_FILE, 'a'){ |f| f.puts msg }
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
# Create an instance of the Daemon and put it into a loop. I borrowed the
|
90
|
-
# method name 'mainloop' from Tk, btw.
|
91
|
-
#
|
92
|
-
DemoDaemon.mainloop
|
93
|
-
rescue Exception => err
|
94
|
-
File.open(LOG_FILE, 'a'){ |fh| fh.puts "Daemon failure: #{err}" }
|
95
|
-
raise
|
96
|
-
end
|
data/examples/demo_daemon_ctl.rb
DELETED
@@ -1,123 +0,0 @@
|
|
1
|
-
############################################################################
|
2
|
-
# demo_daemon_ctl.rb
|
3
|
-
#
|
4
|
-
# This is a command line script for installing and/or running a small
|
5
|
-
# Ruby program as a service. The service will simply write a small bit
|
6
|
-
# of text to a file every 20 seconds. It will also write some text to the
|
7
|
-
# file during the initialization (service_init) step.
|
8
|
-
#
|
9
|
-
# It should take about 10 seconds to start, which is intentional - it's a test
|
10
|
-
# of the service_init hook, so don't be surprised if you see "one moment,
|
11
|
-
# start pending" about 10 times on the command line.
|
12
|
-
#
|
13
|
-
# The file in question is C:\Tmp\win32_daemon_test.log. Feel free to delete
|
14
|
-
# it when you're finished.
|
15
|
-
#
|
16
|
-
# To run the service, you must install it first.
|
17
|
-
#
|
18
|
-
# Usage: ruby demo_daemon_ctl.rb <option>
|
19
|
-
#
|
20
|
-
# Note that you *must* pass this program an option
|
21
|
-
#
|
22
|
-
# Options:
|
23
|
-
# install - Installs the service. The service name is "DemoSvc"
|
24
|
-
# and the display name is "Demo".
|
25
|
-
# start - Starts the service. Make sure you stop it at some point or
|
26
|
-
# you will eventually fill up your filesystem!.
|
27
|
-
# stop - Stops the service.
|
28
|
-
# pause - Pauses the service.
|
29
|
-
# resume - Resumes the service.
|
30
|
-
# uninstall - Uninstalls the service.
|
31
|
-
# delete - Same as uninstall.
|
32
|
-
#
|
33
|
-
# You can also used the Windows Services GUI to start and stop the service.
|
34
|
-
#
|
35
|
-
# To get to the Windows Services GUI just follow:
|
36
|
-
# Start -> Control Panel -> Administrative Tools -> Services
|
37
|
-
############################################################################
|
38
|
-
require 'win32/service'
|
39
|
-
require 'rbconfig'
|
40
|
-
include Win32
|
41
|
-
include RbConfig
|
42
|
-
|
43
|
-
# Make sure you're using the version you think you're using.
|
44
|
-
puts 'VERSION: ' + Service::VERSION
|
45
|
-
|
46
|
-
SERVICE_NAME = 'DemoSvc'
|
47
|
-
SERVICE_DISPLAYNAME = 'Demo'
|
48
|
-
|
49
|
-
# Quote the full path to deal with possible spaces in the path name.
|
50
|
-
ruby = File.join(CONFIG['bindir'], CONFIG['ruby_install_name']).tr('/', '\\')
|
51
|
-
path = ' "' + File.dirname(File.expand_path($0)).tr('/', '\\')
|
52
|
-
path += '\demo_daemon.rb"'
|
53
|
-
cmd = ruby + path
|
54
|
-
|
55
|
-
# You must provide at least one argument.
|
56
|
-
raise ArgumentError, 'No argument provided' unless ARGV[0]
|
57
|
-
|
58
|
-
case ARGV[0].downcase
|
59
|
-
when 'install'
|
60
|
-
Service.new(
|
61
|
-
:service_name => SERVICE_NAME,
|
62
|
-
:display_name => SERVICE_DISPLAYNAME,
|
63
|
-
:description => 'Sample Ruby service',
|
64
|
-
:binary_path_name => cmd
|
65
|
-
)
|
66
|
-
puts 'Service ' + SERVICE_NAME + ' installed'
|
67
|
-
when 'start'
|
68
|
-
if Service.status(SERVICE_NAME).current_state != 'running'
|
69
|
-
Service.start(SERVICE_NAME, nil, 'hello', 'world')
|
70
|
-
while Service.status(SERVICE_NAME).current_state != 'running'
|
71
|
-
puts 'One moment...' + Service.status(SERVICE_NAME).current_state
|
72
|
-
sleep 1
|
73
|
-
end
|
74
|
-
puts 'Service ' + SERVICE_NAME + ' started'
|
75
|
-
else
|
76
|
-
puts 'Already running'
|
77
|
-
end
|
78
|
-
when 'stop'
|
79
|
-
if Service.status(SERVICE_NAME).current_state != 'stopped'
|
80
|
-
Service.stop(SERVICE_NAME)
|
81
|
-
while Service.status(SERVICE_NAME).current_state != 'stopped'
|
82
|
-
puts 'One moment...' + Service.status(SERVICE_NAME).current_state
|
83
|
-
sleep 1
|
84
|
-
end
|
85
|
-
puts 'Service ' + SERVICE_NAME + ' stopped'
|
86
|
-
else
|
87
|
-
puts 'Already stopped'
|
88
|
-
end
|
89
|
-
when 'uninstall', 'delete'
|
90
|
-
if Service.status(SERVICE_NAME).current_state != 'stopped'
|
91
|
-
Service.stop(SERVICE_NAME)
|
92
|
-
end
|
93
|
-
while Service.status(SERVICE_NAME).current_state != 'stopped'
|
94
|
-
puts 'One moment...' + Service.status(SERVICE_NAME).current_state
|
95
|
-
sleep 1
|
96
|
-
end
|
97
|
-
Service.delete(SERVICE_NAME)
|
98
|
-
puts 'Service ' + SERVICE_NAME + ' deleted'
|
99
|
-
when 'pause'
|
100
|
-
if Service.status(SERVICE_NAME).current_state != 'paused'
|
101
|
-
Service.pause(SERVICE_NAME)
|
102
|
-
while Service.status(SERVICE_NAME).current_state != 'paused'
|
103
|
-
puts 'One moment...' + Service.status(SERVICE_NAME).current_state
|
104
|
-
sleep 1
|
105
|
-
end
|
106
|
-
puts 'Service ' + SERVICE_NAME + ' paused'
|
107
|
-
else
|
108
|
-
puts 'Already paused'
|
109
|
-
end
|
110
|
-
when 'resume'
|
111
|
-
if Service.status(SERVICE_NAME).current_state != 'running'
|
112
|
-
Service.resume(SERVICE_NAME)
|
113
|
-
while Service.status(SERVICE_NAME).current_state != 'running'
|
114
|
-
puts 'One moment...' + Service.status(SERVICE_NAME).current_state
|
115
|
-
sleep 1
|
116
|
-
end
|
117
|
-
puts 'Service ' + SERVICE_NAME + ' resumed'
|
118
|
-
else
|
119
|
-
puts 'Already running'
|
120
|
-
end
|
121
|
-
else
|
122
|
-
raise ArgumentError, 'unknown option: ' + ARGV[0]
|
123
|
-
end
|
data/examples/demo_services.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
#######################################################################
|
2
|
-
# demo_services.rb
|
3
|
-
#
|
4
|
-
# Test script for general futzing that shows off the basic
|
5
|
-
# capabilities of this library. Modify as you see fit.
|
6
|
-
#
|
7
|
-
# You can run this sample program via the "example:services" task.
|
8
|
-
#######################################################################
|
9
|
-
require 'win32/service'
|
10
|
-
include Win32
|
11
|
-
|
12
|
-
puts "VERSION: " + Service::VERSION
|
13
|
-
|
14
|
-
p Service.exists?('Schedule')
|
15
|
-
p Service.exists?('bogusxxx')
|
16
|
-
|
17
|
-
status = Service.status('Schedule')
|
18
|
-
p status
|
19
|
-
|
20
|
-
info = Service.config_info('Schedule')
|
21
|
-
|
22
|
-
print "\n\nShowing config info for Schedule service\n\n"
|
23
|
-
p info
|
24
|
-
|
25
|
-
print "\n\nAbout to show all services\n\n"
|
26
|
-
sleep 10
|
27
|
-
|
28
|
-
Service.services{ |struct|
|
29
|
-
p struct
|
30
|
-
}
|
data/test/test_win32_daemon.rb
DELETED
@@ -1,58 +0,0 @@
|
|
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.10', 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
|
data/test/test_win32_service.rb
DELETED
@@ -1,468 +0,0 @@
|
|
1
|
-
##########################################################################
|
2
|
-
# test_win32_service.rb
|
3
|
-
#
|
4
|
-
# Tests for the Win32::Service class. Some tests are skipped unless
|
5
|
-
# run with admin privileges either because they are somewhat invasive,
|
6
|
-
# or because they take too long.
|
7
|
-
##########################################################################
|
8
|
-
require 'test-unit'
|
9
|
-
require 'win32/security'
|
10
|
-
require 'win32/service'
|
11
|
-
require 'socket'
|
12
|
-
|
13
|
-
class TC_Win32_Service < Test::Unit::TestCase
|
14
|
-
def self.startup
|
15
|
-
@@host = Socket.gethostname
|
16
|
-
@@service_name = 'stisvc'
|
17
|
-
@@elevated = Win32::Security.elevated_security?
|
18
|
-
end
|
19
|
-
|
20
|
-
def setup
|
21
|
-
@display_name = 'Windows Image Acquisition (WIA)'
|
22
|
-
@service_name = 'stisvc'
|
23
|
-
@service_stat = nil
|
24
|
-
@services = []
|
25
|
-
@elevated = Win32::Security.elevated_security?
|
26
|
-
|
27
|
-
@singleton_methods = Win32::Service.methods.map{ |m| m.to_s }
|
28
|
-
@instance_methods = Win32::Service.instance_methods.map{ |m| m.to_s }
|
29
|
-
end
|
30
|
-
|
31
|
-
def omit_unless_elevated
|
32
|
-
omit_unless(@elevated, "Skipped unless run with admin privileges")
|
33
|
-
end
|
34
|
-
|
35
|
-
def start_service(service)
|
36
|
-
status = Win32::Service.status(@service_name).current_state
|
37
|
-
|
38
|
-
if @elevated
|
39
|
-
if status == 'paused'
|
40
|
-
Win32::Service.resume(service)
|
41
|
-
else
|
42
|
-
unless ['running', 'start pending'].include?(status)
|
43
|
-
Win32::Service.start(service)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
wait_for_status('running')
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def stop_service(service)
|
51
|
-
status = Win32::Service.status(@service_name).current_state
|
52
|
-
if @elevated
|
53
|
-
unless ['stopped', 'stop pending'].include?(status)
|
54
|
-
Win32::Service.stop(service)
|
55
|
-
end
|
56
|
-
wait_for_status('stopped')
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
# Helper method that waits for a status to change its state since state
|
61
|
-
# changes aren't usually instantaneous.
|
62
|
-
def wait_for_status(status)
|
63
|
-
sleep 0.1 while Win32::Service.status(@service_name).current_state != status
|
64
|
-
end
|
65
|
-
|
66
|
-
test "version number is expected value" do
|
67
|
-
assert_equal('0.8.10', Win32::Service::VERSION)
|
68
|
-
end
|
69
|
-
|
70
|
-
test "services basic functionality" do
|
71
|
-
assert_respond_to(Win32::Service, :services)
|
72
|
-
end
|
73
|
-
|
74
|
-
test "services with no arguments works as expected" do
|
75
|
-
assert_nothing_raised{ Win32::Service.services }
|
76
|
-
end
|
77
|
-
|
78
|
-
test "services with explicit host works as expected" do
|
79
|
-
assert_nothing_raised{ Win32::Service.services(@@host) }
|
80
|
-
end
|
81
|
-
|
82
|
-
test "services with explicit host and group works as expected" do
|
83
|
-
assert_nothing_raised{ Win32::Service.services(@@host, 'network') }
|
84
|
-
end
|
85
|
-
|
86
|
-
test "services method returns an array without a block" do
|
87
|
-
assert_nothing_raised{ @services = Win32::Service.services }
|
88
|
-
assert_kind_of(Array, @services)
|
89
|
-
assert_kind_of(Struct::ServiceInfo, @services[0])
|
90
|
-
end
|
91
|
-
|
92
|
-
test "services method yields service objects when a block is provided" do
|
93
|
-
assert_nothing_raised{ Win32::Service.services{ |s| @services << s } }
|
94
|
-
assert_kind_of(Array, @services)
|
95
|
-
assert_kind_of(Struct::ServiceInfo, @services[0])
|
96
|
-
end
|
97
|
-
|
98
|
-
test "the host argument must be a string or an error is raised" do
|
99
|
-
assert_raise(TypeError){ Win32::Service.services(1) }
|
100
|
-
end
|
101
|
-
|
102
|
-
test "the group argument must be a string or an error is raised" do
|
103
|
-
assert_raise(TypeError){ Win32::Service.services(nil, 1) }
|
104
|
-
end
|
105
|
-
|
106
|
-
test "the services method only accepts 2 arguments" do
|
107
|
-
assert_raise(ArgumentError){ Win32::Service.services(nil, 'network', 1) }
|
108
|
-
end
|
109
|
-
|
110
|
-
test "a valid hostname must be provided or an error is raised" do
|
111
|
-
omit_unless_elevated
|
112
|
-
assert_raise(SystemCallError){ Win32::Service.services('bogus') }
|
113
|
-
end
|
114
|
-
|
115
|
-
test "delete method basic functionality" do
|
116
|
-
assert_respond_to(Win32::Service, :delete)
|
117
|
-
end
|
118
|
-
|
119
|
-
test "a service name must be provided to the delete method" do
|
120
|
-
assert_raise(ArgumentError){ Win32::Service.delete }
|
121
|
-
end
|
122
|
-
|
123
|
-
test "delete method raises an error if a bogus service name is provided" do
|
124
|
-
omit_unless_elevated
|
125
|
-
assert_raise(SystemCallError){ Win32::Service.delete('bogus') }
|
126
|
-
end
|
127
|
-
|
128
|
-
test "delete method raises an error if a bogus host name is provided" do
|
129
|
-
omit_unless_elevated
|
130
|
-
assert_raise(SystemCallError){ Win32::Service.delete('bogus', 'bogus') }
|
131
|
-
end
|
132
|
-
|
133
|
-
test "delete method only accepts up to two arguments" do
|
134
|
-
assert_raise(ArgumentError){ Win32::Service.delete('x', 'y', 'z') }
|
135
|
-
end
|
136
|
-
|
137
|
-
test "pause basic functionality" do
|
138
|
-
assert_respond_to(Win32::Service, :pause)
|
139
|
-
end
|
140
|
-
|
141
|
-
test "resume basic functionality" do
|
142
|
-
assert_respond_to(Win32::Service, :resume)
|
143
|
-
end
|
144
|
-
|
145
|
-
test "pause and resume work as expected" do
|
146
|
-
omit_unless_elevated
|
147
|
-
start_service(@service_name)
|
148
|
-
|
149
|
-
assert_nothing_raised{ Win32::Service.pause(@service_name) }
|
150
|
-
wait_for_status('paused')
|
151
|
-
|
152
|
-
assert_nothing_raised{ Win32::Service.resume(@service_name) }
|
153
|
-
wait_for_status('running')
|
154
|
-
end
|
155
|
-
|
156
|
-
test "pausing an already paused service is harmless" do
|
157
|
-
omit_unless_elevated
|
158
|
-
start_service(@service_name)
|
159
|
-
|
160
|
-
assert_nothing_raised{ Win32::Service.pause(@service_name) }
|
161
|
-
wait_for_status('paused')
|
162
|
-
assert_nothing_raised{ Win32::Service.pause(@service_name) }
|
163
|
-
end
|
164
|
-
|
165
|
-
test "pause requires a service name as an argument" do
|
166
|
-
assert_raise(ArgumentError){ Win32::Service.pause }
|
167
|
-
end
|
168
|
-
|
169
|
-
test "pausing an unrecognized service name raises an error" do
|
170
|
-
assert_raise(SystemCallError){ Win32::Service.pause('bogus') }
|
171
|
-
end
|
172
|
-
|
173
|
-
test "pausing a service on an unrecognized host raises an error" do
|
174
|
-
omit_unless_elevated
|
175
|
-
assert_raise(SystemCallError){ Win32::Service.pause('W32Time', 'bogus') }
|
176
|
-
end
|
177
|
-
|
178
|
-
test "pause method accepts a maximum of two arguments" do
|
179
|
-
assert_raise(ArgumentError){ Win32::Service.pause('x', 'y', 'z') }
|
180
|
-
end
|
181
|
-
|
182
|
-
test "resume method requires a service name" do
|
183
|
-
assert_raise(ArgumentError){ Win32::Service.resume }
|
184
|
-
end
|
185
|
-
|
186
|
-
test "resume method with an unrecognized service name raises an error" do
|
187
|
-
assert_raise(SystemCallError){ Win32::Service.resume('bogus') }
|
188
|
-
end
|
189
|
-
|
190
|
-
test "resume method with an unrecognized host name raises an error" do
|
191
|
-
omit_unless_elevated
|
192
|
-
assert_raise(SystemCallError){ Win32::Service.resume('W32Time', 'bogus') }
|
193
|
-
end
|
194
|
-
|
195
|
-
test "resume method accepts a maximum of two arguments" do
|
196
|
-
assert_raise(ArgumentError){ Win32::Service.resume('W32Time', @@host, true) }
|
197
|
-
end
|
198
|
-
|
199
|
-
test "stop method basic functionality" do
|
200
|
-
assert_respond_to(Win32::Service, :stop)
|
201
|
-
end
|
202
|
-
|
203
|
-
test "start method basic functionality" do
|
204
|
-
assert_respond_to(Win32::Service, :start)
|
205
|
-
end
|
206
|
-
|
207
|
-
test "stop and start methods work as expected" do
|
208
|
-
omit_unless_elevated
|
209
|
-
start_service(@service_name)
|
210
|
-
|
211
|
-
assert_nothing_raised{ Win32::Service.stop(@service_name) }
|
212
|
-
wait_for_status('stopped')
|
213
|
-
|
214
|
-
assert_nothing_raised{ Win32::Service.start(@service_name) }
|
215
|
-
wait_for_status('running')
|
216
|
-
end
|
217
|
-
|
218
|
-
test "attempting to stop a stopped service raises an error" do
|
219
|
-
omit_unless_elevated
|
220
|
-
start_service(@service_name)
|
221
|
-
|
222
|
-
assert_nothing_raised{ Win32::Service.stop(@service_name) }
|
223
|
-
wait_for_status('stopped')
|
224
|
-
assert_raise(SystemCallError){ Win32::Service.stop(@service_name) }
|
225
|
-
|
226
|
-
assert_nothing_raised{ Win32::Service.start(@service_name) }
|
227
|
-
end
|
228
|
-
|
229
|
-
test "stop method requires a service name" do
|
230
|
-
assert_raise(ArgumentError){ Win32::Service.stop }
|
231
|
-
end
|
232
|
-
|
233
|
-
test "stop method raises an error if the service name is unrecognized" do
|
234
|
-
assert_raise(SystemCallError){ Win32::Service.stop('bogus') }
|
235
|
-
end
|
236
|
-
|
237
|
-
test "stop method raises an error if the host is unrecognized" do
|
238
|
-
omit_unless_elevated
|
239
|
-
assert_raise(SystemCallError){ Win32::Service.stop('W32Time', 'bogus') }
|
240
|
-
end
|
241
|
-
|
242
|
-
test "stop metho accepts a maximum of two arguments" do
|
243
|
-
assert_raise(ArgumentError){ Win32::Service.stop('W32Time', @@host, true) }
|
244
|
-
end
|
245
|
-
|
246
|
-
test "start method requires a service name" do
|
247
|
-
assert_raise(ArgumentError){ Win32::Service.start }
|
248
|
-
end
|
249
|
-
|
250
|
-
test "attempting to start a running service raises an error" do
|
251
|
-
omit_unless_elevated
|
252
|
-
start_service(@service_name)
|
253
|
-
assert_raise(SystemCallError){ Win32::Service.start(@service_name) }
|
254
|
-
end
|
255
|
-
|
256
|
-
test "attempting to start an unrecognized service raises an error" do
|
257
|
-
assert_raise(SystemCallError){ Win32::Service.start('bogus') }
|
258
|
-
end
|
259
|
-
|
260
|
-
test "attempting to start a service on an unknown host raises an error" do
|
261
|
-
omit_unless_elevated
|
262
|
-
assert_raise(SystemCallError){ Win32::Service.start('bogus', 'bogus') }
|
263
|
-
end
|
264
|
-
|
265
|
-
test "stop requires at least one argument" do
|
266
|
-
assert_raise(ArgumentError){ Win32::Service.stop }
|
267
|
-
end
|
268
|
-
|
269
|
-
test "stop raises an error with an unrecognized service name" do
|
270
|
-
assert_raise(SystemCallError){ Win32::Service.stop('bogus') }
|
271
|
-
end
|
272
|
-
|
273
|
-
test "stop raises an error with an unrecognized host" do
|
274
|
-
omit_unless_elevated
|
275
|
-
assert_raise(SystemCallError){ Win32::Service.stop('W32Time', 'bogus') }
|
276
|
-
end
|
277
|
-
|
278
|
-
test "stop accepts a maximum of 2 arguments" do
|
279
|
-
assert_raise(ArgumentError){ Win32::Service.stop('a', 'b', 'c') }
|
280
|
-
end
|
281
|
-
|
282
|
-
test "status basic functionality" do
|
283
|
-
assert_respond_to(Win32::Service, :status)
|
284
|
-
assert_nothing_raised{ Win32::Service.status(@service_name) }
|
285
|
-
assert_kind_of(Struct::ServiceStatus, Win32::Service.status(@service_name))
|
286
|
-
end
|
287
|
-
|
288
|
-
test "get_service_name basic functionality" do
|
289
|
-
assert_respond_to(Win32::Service, :get_service_name)
|
290
|
-
assert_nothing_raised{ Win32::Service.get_service_name(@display_name) }
|
291
|
-
assert_kind_of(String, Win32::Service.get_service_name(@display_name))
|
292
|
-
end
|
293
|
-
|
294
|
-
test "get_service_name returns expected results" do
|
295
|
-
assert_equal(@service_name, Win32::Service.get_service_name(@display_name))
|
296
|
-
end
|
297
|
-
|
298
|
-
test "getservicename is an alias for get_service_name" do
|
299
|
-
assert_respond_to(Win32::Service, :getservicename)
|
300
|
-
assert_alias_method(Win32::Service, :getservicename, :get_service_name)
|
301
|
-
end
|
302
|
-
|
303
|
-
test "get_service_name requires at least one argument" do
|
304
|
-
assert_raise(ArgumentError){ Win32::Service.get_service_name }
|
305
|
-
end
|
306
|
-
|
307
|
-
test "get_service_name raises an error if a bogus service name is provided" do
|
308
|
-
assert_raise(SystemCallError){ Win32::Service.get_service_name('bogus') }
|
309
|
-
end
|
310
|
-
|
311
|
-
test "get_service_name raises an error if a bogus host is provided" do
|
312
|
-
omit_unless_elevated
|
313
|
-
assert_raise(SystemCallError){ Win32::Service.get_service_name('foo', 'bogus') }
|
314
|
-
end
|
315
|
-
|
316
|
-
test "get_service_name accepts a maximum of two arguments" do
|
317
|
-
assert_raise(ArgumentError){ Win32::Service.get_service_name('x', 'y', 'z') }
|
318
|
-
end
|
319
|
-
|
320
|
-
test "get_display_name basic functionality" do
|
321
|
-
assert_respond_to(Win32::Service, :get_display_name)
|
322
|
-
assert_nothing_raised{ Win32::Service.get_display_name(@service_name) }
|
323
|
-
assert_kind_of(String, Win32::Service.get_display_name(@service_name))
|
324
|
-
end
|
325
|
-
|
326
|
-
test "get_display_name returns expected results" do
|
327
|
-
assert_equal(@display_name, Win32::Service.get_display_name(@service_name))
|
328
|
-
end
|
329
|
-
|
330
|
-
test "getdisplayname is an alias for get_display_name" do
|
331
|
-
assert_respond_to(Win32::Service, :getdisplayname)
|
332
|
-
assert_alias_method(Win32::Service, :getdisplayname, :get_display_name)
|
333
|
-
end
|
334
|
-
|
335
|
-
test "get_display_name requires at least one argument" do
|
336
|
-
assert_raise(ArgumentError){ Win32::Service.get_display_name }
|
337
|
-
end
|
338
|
-
|
339
|
-
test "get_display_name raises an error if the service does not exist" do
|
340
|
-
assert_raise(SystemCallError){ Win32::Service.get_display_name('bogus') }
|
341
|
-
end
|
342
|
-
|
343
|
-
test "get_display_name raises an error if a bad host name is provided" do
|
344
|
-
omit_unless_elevated
|
345
|
-
assert_raise(SystemCallError){ Win32::Service.get_display_name('W32Time', 'bogus') }
|
346
|
-
end
|
347
|
-
|
348
|
-
test "get_display_name takes a maximum of two arguments" do
|
349
|
-
assert_raise(ArgumentError){ Win32::Service.get_display_name('x', 'y', 'z') }
|
350
|
-
end
|
351
|
-
|
352
|
-
test "exists method basic functionality" do
|
353
|
-
assert_respond_to(Win32::Service, :exists?)
|
354
|
-
assert_boolean(Win32::Service.exists?('W32Time'))
|
355
|
-
assert_nothing_raised{ Win32::Service.exists?('W32Time') }
|
356
|
-
end
|
357
|
-
|
358
|
-
test "exists method returns expected results" do
|
359
|
-
assert_true(Win32::Service.exists?('W32Time'))
|
360
|
-
assert_false(Win32::Service.exists?('foobar'))
|
361
|
-
end
|
362
|
-
|
363
|
-
test "exists method requires at least one argument or an error is raised" do
|
364
|
-
assert_raises(ArgumentError){ Win32::Service.exists? }
|
365
|
-
end
|
366
|
-
|
367
|
-
test "exists method raises an error if a bogus host is passed" do
|
368
|
-
omit_unless_elevated
|
369
|
-
assert_raises(SystemCallError){ Win32::Service.exists?('foo', 'bogus') }
|
370
|
-
end
|
371
|
-
|
372
|
-
test "exists method only accepts up to two arguments" do
|
373
|
-
assert_raises(ArgumentError){
|
374
|
-
Win32::Service.exists?('foo', 'bar', 'baz')
|
375
|
-
}
|
376
|
-
end
|
377
|
-
|
378
|
-
test "scm security constants are defined" do
|
379
|
-
assert_not_nil(Win32::Service::MANAGER_ALL_ACCESS)
|
380
|
-
assert_not_nil(Win32::Service::MANAGER_CREATE_SERVICE)
|
381
|
-
assert_not_nil(Win32::Service::MANAGER_CONNECT)
|
382
|
-
assert_not_nil(Win32::Service::MANAGER_ENUMERATE_SERVICE)
|
383
|
-
assert_not_nil(Win32::Service::MANAGER_LOCK)
|
384
|
-
assert_not_nil(Win32::Service::MANAGER_QUERY_LOCK_STATUS)
|
385
|
-
end
|
386
|
-
|
387
|
-
test "service specific constants are defined" do
|
388
|
-
assert_not_nil(Win32::Service::ALL_ACCESS)
|
389
|
-
assert_not_nil(Win32::Service::CHANGE_CONFIG)
|
390
|
-
assert_not_nil(Win32::Service::ENUMERATE_DEPENDENTS)
|
391
|
-
assert_not_nil(Win32::Service::INTERROGATE)
|
392
|
-
assert_not_nil(Win32::Service::PAUSE_CONTINUE)
|
393
|
-
assert_not_nil(Win32::Service::QUERY_CONFIG)
|
394
|
-
assert_not_nil(Win32::Service::QUERY_STATUS)
|
395
|
-
assert_not_nil(Win32::Service::STOP)
|
396
|
-
assert_not_nil(Win32::Service::START)
|
397
|
-
assert_not_nil(Win32::Service::USER_DEFINED_CONTROL)
|
398
|
-
end
|
399
|
-
|
400
|
-
test "service type constants are defined" do
|
401
|
-
assert_not_nil(Win32::Service::FILE_SYSTEM_DRIVER)
|
402
|
-
assert_not_nil(Win32::Service::KERNEL_DRIVER)
|
403
|
-
assert_not_nil(Win32::Service::WIN32_OWN_PROCESS)
|
404
|
-
assert_not_nil(Win32::Service::WIN32_SHARE_PROCESS)
|
405
|
-
assert_not_nil(Win32::Service::INTERACTIVE_PROCESS)
|
406
|
-
end
|
407
|
-
|
408
|
-
test "service start option constants are defined" do
|
409
|
-
assert_not_nil(Win32::Service::AUTO_START)
|
410
|
-
assert_not_nil(Win32::Service::BOOT_START)
|
411
|
-
assert_not_nil(Win32::Service::DEMAND_START)
|
412
|
-
assert_not_nil(Win32::Service::DISABLED)
|
413
|
-
assert_not_nil(Win32::Service::SYSTEM_START)
|
414
|
-
end
|
415
|
-
|
416
|
-
test "service error control constants are defined" do
|
417
|
-
assert_not_nil(Win32::Service::ERROR_IGNORE)
|
418
|
-
assert_not_nil(Win32::Service::ERROR_NORMAL)
|
419
|
-
assert_not_nil(Win32::Service::ERROR_SEVERE)
|
420
|
-
assert_not_nil(Win32::Service::ERROR_CRITICAL)
|
421
|
-
end
|
422
|
-
|
423
|
-
test "service state constants are defined" do
|
424
|
-
assert_not_nil(Win32::Service::CONTINUE_PENDING)
|
425
|
-
assert_not_nil(Win32::Service::PAUSE_PENDING)
|
426
|
-
assert_not_nil(Win32::Service::PAUSED)
|
427
|
-
assert_not_nil(Win32::Service::RUNNING)
|
428
|
-
assert_not_nil(Win32::Service::START_PENDING)
|
429
|
-
assert_not_nil(Win32::Service::STOP_PENDING)
|
430
|
-
assert_not_nil(Win32::Service::STOPPED)
|
431
|
-
end
|
432
|
-
|
433
|
-
test "internal ffi functions are not public as singleton methods" do
|
434
|
-
assert_false(@singleton_methods.include?('CloseHandle'))
|
435
|
-
assert_false(@singleton_methods.include?('ControlService'))
|
436
|
-
assert_false(@singleton_methods.include?('DeleteService'))
|
437
|
-
end
|
438
|
-
|
439
|
-
test "internal ffi functions are not public as instance methods" do
|
440
|
-
assert_false(@instance_methods.include?('CloseHandle'))
|
441
|
-
assert_false(@instance_methods.include?('ControlService'))
|
442
|
-
assert_false(@instance_methods.include?('DeleteService'))
|
443
|
-
end
|
444
|
-
|
445
|
-
def teardown
|
446
|
-
@display_name = nil
|
447
|
-
@service_name = nil
|
448
|
-
@service_stat = nil
|
449
|
-
@services = nil
|
450
|
-
end
|
451
|
-
|
452
|
-
def self.shutdown
|
453
|
-
@@host = nil
|
454
|
-
status = Win32::Service.status(@@service_name).current_state
|
455
|
-
|
456
|
-
if @elevated
|
457
|
-
if status == 'paused'
|
458
|
-
Win32::Service.resume(@@service_name)
|
459
|
-
end
|
460
|
-
|
461
|
-
unless ['running', 'start pending'].include?(status)
|
462
|
-
Win32::Service.start(@@service_name)
|
463
|
-
end
|
464
|
-
end
|
465
|
-
|
466
|
-
@@elevated = nil
|
467
|
-
end
|
468
|
-
end
|