win-service 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
File without changes
@@ -0,0 +1,3 @@
1
+ === 0.1.0 / 2011-05-05
2
+
3
+ * Initial release
@@ -0,0 +1,16 @@
1
+ Manifest.txt
2
+ History.txt
3
+ README.txt
4
+ Rakefile
5
+ win-service.gemspec
6
+ lib/win/service.rb
7
+ lib/win/service_controller.rb
8
+ lib/win/service_controller/service_controller.rb
9
+ lib/win/service_controller/service_errors.rb
10
+ lib/win/service_controller/unix_service.rb
11
+ lib/win/service_controller/windows_service.rb
12
+ spec/service_controller_spec.rb
13
+ spec/service_spec.rb
14
+ spec/spec_helper.rb
15
+ spec/unix_service_spec.rb
16
+ spec/windows_service_spec.rb
@@ -0,0 +1,60 @@
1
+ = win_service
2
+
3
+ http://rubyforge.org/projects/win-service/
4
+
5
+ == DESCRIPTION:
6
+
7
+ A ruby gem that will allow the basic functions of getting the status, stopping and starting of a windows service from both a windows and a mac os x operating system.
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ == SYNOPSIS:
12
+
13
+ $ irb
14
+ >> require 'win/service'
15
+ >> service = Win::Service.new('SERVICE_NAME', 'IP_OF_SERVER', 'USER_NAME', 'PASSWORD')
16
+ >> service.status
17
+ >> service.start
18
+ >> service.pause
19
+ >> service.resume
20
+ >> service.stop
21
+
22
+ == REQUIREMENTS:
23
+
24
+ == INSTALL:
25
+
26
+ rake rspec (optional)
27
+ rake install
28
+
29
+ == DEVELOPERS:
30
+
31
+ After checking out the source, run:
32
+
33
+ $ rake install
34
+
35
+ This task will install the gem, any missing dependencies and generate the RDoc.
36
+
37
+ == LICENSE:
38
+
39
+ (The MIT License)
40
+
41
+ Copyright (c) 2011 FIX
42
+
43
+ Permission is hereby granted, free of charge, to any person obtaining
44
+ a copy of this software and associated documentation files (the
45
+ 'Software'), to deal in the Software without restriction, including
46
+ without limitation the rights to use, copy, modify, merge, publish,
47
+ distribute, sublicense, and/or sell copies of the Software, and to
48
+ permit persons to whom the Software is furnished to do so, subject to
49
+ the following conditions:
50
+
51
+ The above copyright notice and this permission notice shall be
52
+ included in all copies or substantial portions of the Software.
53
+
54
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
55
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
56
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
57
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
58
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
59
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
60
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,108 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'rake'
5
+ require 'rake/clean'
6
+ require 'rspec/version'
7
+ require 'rspec/core/rake_task'
8
+ require 'rake/rdoctask'
9
+ require 'rbconfig'
10
+ require 'hoe'
11
+ include Config
12
+
13
+ # Hoe.plugin :compiler
14
+ # Hoe.plugin :gem_prelude_sucks
15
+ # Hoe.plugin :inline
16
+ # Hoe.plugin :racc
17
+ # Hoe.plugin :rubyforge
18
+
19
+ Hoe.spec 'win-service' do
20
+ self.name = 'win-service'
21
+ self.version = '0.1.0'
22
+ self.author = 'James T. Pavlic'
23
+ self.email = 'james_pavlic@hotmail.com'
24
+ self.summary = 'An interface for MS Windows services'
25
+ self.remote_rdoc_dir = '' # Release to root
26
+ self.url = 'http://codinghappy.blogspot.com/'
27
+
28
+ self.extra_rdoc_files = [
29
+ 'History.txt',
30
+ 'README.txt',
31
+ 'Manifest.txt'
32
+ ]
33
+
34
+ self.description = <<-EOF
35
+ A ruby gem that will allow the basic functions of getting the status,
36
+ stopping and starting of a windows service from both a windows and a mac os x operating system.
37
+ EOF
38
+ end
39
+
40
+ desc 'Install the (non-gem) win-service library.'
41
+ task :install_non_gem do
42
+ install_dir = CONFIG['sitelibdir']
43
+ Dir.mkdir(install_dir) unless File.exists?(install_dir)
44
+ FileUtils.cp_r('lib/win', install_dir, :verbose => true)
45
+ end
46
+
47
+ desc 'Uninstall the (non-gem) win-service library.'
48
+ task :uninstall_non_gem do
49
+ install_dir = File.join(CONFIG['sitelibdir'], 'win')
50
+ FileUtils.rm_r(install_dir, :verbose => true) if File.exists?(install_dir)
51
+ end
52
+
53
+ desc "Run the test suite for the win-service library."
54
+ RSpec::Core::RakeTask.new('rspec') do |t|
55
+ t.pattern = '**/*_spec.rb'
56
+ end
57
+
58
+ desc "Install the win-service gem"
59
+ task :install do
60
+ spec = Gem::Specification.new do |gem|
61
+ gem.name = 'win-service'
62
+ gem.version = '0.1.0'
63
+ gem.authors = ['James T. Pavlic']
64
+ gem.email = 'james_pavlic@hotmail.com'
65
+ gem.license = 'The MIT License'
66
+ gem.homepage = 'https://github.com/jpavlic/win-service'
67
+ gem.platform = Gem::Platform::RUBY
68
+ gem.summary = 'An interface for MS Windows services'
69
+ gem.add_development_dependency('rspec')
70
+ gem.has_rdoc = true
71
+ gem.files = Dir['**/*'].delete_if { |f|
72
+ }
73
+
74
+ gem.extra_rdoc_files = [
75
+ 'History.txt',
76
+ 'README.txt',
77
+ 'Manifest.txt'
78
+ ]
79
+
80
+ gem.rubyforge_project = 'win-service'
81
+ gem.required_ruby_version = '>= 1.8.7'
82
+
83
+ gem.description = <<-EOF
84
+ A ruby gem that will allow the basic functions of getting the status,
85
+ stopping and starting of a windows service from both a windows and a mac os x operating system.
86
+ EOF
87
+ end
88
+
89
+ Gem::Builder.new(spec).build
90
+
91
+ file = Dir['win-service*.gem'].first
92
+ sh "gem install #{file}"
93
+ end
94
+
95
+ Rake::RDocTask.new do |rdoc|
96
+ files = [ 'README.txt',
97
+ 'History.txt',
98
+ 'Manifest.txt',
99
+ 'doc/*.rdoc',
100
+ 'spec/*_spec.rb',
101
+ 'lib/**/*.rb']
102
+ rdoc.rdoc_files.add(files)
103
+ rdoc.title = 'win-service documentation'
104
+ rdoc.rdoc_dir = 'doc'
105
+ rdoc.options << '--line-number' << '--inline-source'
106
+ end
107
+
108
+ # vim: syntax=ruby
@@ -0,0 +1,36 @@
1
+ require 'rbconfig'
2
+ require 'win/service_controller'
3
+
4
+ module Win
5
+ class Service
6
+ VERSION = '0.1.0'
7
+ include Win::ServiceController
8
+
9
+ def initialize(service_name, service_address, user_name, user_password)
10
+ @name = service_name
11
+ @host = service_address
12
+ @user = user_name
13
+ @password = user_password
14
+ end
15
+
16
+ def start
17
+ start_service
18
+ end
19
+
20
+ def stop
21
+ stop_service
22
+ end
23
+
24
+ def pause
25
+ pause_service
26
+ end
27
+
28
+ def resume
29
+ resume_service
30
+ end
31
+
32
+ def status
33
+ service_status
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,2 @@
1
+ require 'win/service_controller/service_controller'
2
+ require 'win/service_controller/service_errors'
@@ -0,0 +1,14 @@
1
+ require 'win/service_controller/unix_service'
2
+ require 'win/service_controller/windows_service'
3
+
4
+ module Win
5
+ module ServiceController
6
+ def self.included(clz)
7
+ if Config::CONFIG['host_os'] =~ /mingw32/
8
+ clz.send :include, WindowsService
9
+ else
10
+ clz.send :include, UnixService
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,57 @@
1
+ module Win
2
+ module ServiceErrors
3
+ class Error
4
+ attr_reader :error
5
+
6
+ def initialize(error)
7
+ @error = error
8
+ end
9
+ end
10
+
11
+ class Errors
12
+ @errors = {
13
+ "0x0000041B"=> "A stop control has been sent to a service that other running services are dependent on.",
14
+ "0x0000041C" => "The requested control is not valid for this service.",
15
+ "0x0000041D" => "The service did not respond to the start or control request in a timely fashion.",
16
+ "0x0000041E" => "A thread could not be created for the service.",
17
+ "0x0000041F" => "The service database is locked.",
18
+ "0x00000420" => "An instance of the service is already running.",
19
+ "0x00000421" => "The account name is invalid or does not exist, or the password is invalid for the account name specified.",
20
+ "0x00000422" => "The service cannot be started, either because it is disabled or because it has no enabled devices associated with it.",
21
+ "0x00000423" => "Circular service dependency was specified.",
22
+ "0x00000424" => "The specified service does not exist as an installed service.",
23
+ "0x00000425" => "The service cannot accept control messages at this time.",
24
+ "0x00000426" => "The service has not been started.",
25
+ "0x00000427" => "The service process could not connect to the service controller.",
26
+ "0x00000428" => "An exception occurred in the service when handling the control request.",
27
+ "0x00000429" => "The database specified does not exist.",
28
+ "0x0000042A" => "The service has returned a service-specific error code.",
29
+ "0x0000042B" => "The process terminated unexpectedly.",
30
+ "0x0000042C" => "The dependency service or group failed to start.",
31
+ "0x0000042D" => "The service did not start due to a logon failure.",
32
+ "0x0000042E" => "After starting, the service hung in a start-pending state.",
33
+ "0x0000042F" => "The specified service database lock is invalid.",
34
+ "0x00000430" => "The specified service has been marked for deletion.",
35
+ "0x00000431" => "The specified service already exists.",
36
+ "0x00000432" => "The system is currently running with the last-known-good configuration.",
37
+ "0x00000433" => "The dependency service does not exist or has been marked for deletion.",
38
+ "0x00000434" => "The current boot has already been accepted for use as the last-known-good control set.",
39
+ "0x00000435" => "No attempts to start the service have been made since the last boot.",
40
+ "0x00000436" => "The name is already in use as either a service name or a service display name.",
41
+ "0x00000437" => "The account specified for this service is different from the account specified for other services running in the same process.",
42
+ "0x00000438" => "Failure actions can only be set for Win32 services, not for drivers.",
43
+ "0x00000439" => "This service runs in the same process as the service control manager. Therefore, the service control manager cannot take action if this service's process terminates unexpectedly.",
44
+ "0x0000043A" => "No recovery program has been configured for this service.",
45
+ "0x0000043B" => "The executable program that this service is configured to run in does not implement the service."
46
+ }
47
+
48
+ def self.error_from_code(code)
49
+ result = @errors[code]
50
+
51
+ return Error.new("#{code}") if result.nil?
52
+
53
+ Error.new(result)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,51 @@
1
+ require 'open3'
2
+
3
+ module Win
4
+ module ServiceController
5
+ module UnixService
6
+ def start_service
7
+ execute_net_rpc_command :start
8
+ end
9
+
10
+ def stop_service
11
+ execute_net_rpc_command :stop
12
+ end
13
+
14
+ def service_status
15
+ result = execute_net_rpc_command :status
16
+ status = remove_tabs_from_string(result).split("\n")[0].scan(/\w+/)
17
+ return status[status.size-1]
18
+ end
19
+
20
+ def pause_service
21
+ execute_net_rpc_command :pause
22
+ end
23
+
24
+ def resume_service
25
+ execute_net_rpc_command :resume
26
+ end
27
+
28
+ private
29
+
30
+ def execute_net_rpc_command(command)
31
+ stdin, stdout, stderr = Open3.popen3(net_rpc_for command.to_s)
32
+ out = stdout.read
33
+ err = stderr.read
34
+
35
+ error_code = err.scan(/0x00000\d*/)[0] if err.size > 0
36
+ error_code = err.gsub("\n", "") if error_code.nil?
37
+
38
+ raise ServiceErrors::Errors.error_from_code(error_code).error unless err.size == 0
39
+ out if command.to_s == 'status'
40
+ end
41
+
42
+ def net_rpc_for(command)
43
+ "net rpc -I #{@host} -U #{@user}%#{@password} service #{command} #{@name}"
44
+ end
45
+
46
+ def remove_tabs_from_string(result)
47
+ result.gsub("\t", "")
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,65 @@
1
+ module Win
2
+ module ServiceController
3
+ module WindowsService
4
+ def start_service
5
+ execute_service_control_command(service_control_for :start)
6
+ end
7
+
8
+ def stop_service
9
+ execute_service_control_command(service_control_for :stop)
10
+ end
11
+
12
+ def pause_service
13
+ execute_service_control_command(service_control_for :pause)
14
+ end
15
+
16
+ def resume_service
17
+ execute_service_control_command(service_control_for :continue)
18
+ end
19
+
20
+ def service_status
21
+ result = execute_service_control_command(service_control_for :query)
22
+
23
+ status = remove_tabs_from_string(result).split("\n").find_all{|item| item =~ /STATE/}[0].scan(/\w+/).last.downcase
24
+ status = "pending" if status.include? "pending"
25
+
26
+ status
27
+ end
28
+
29
+ private
30
+
31
+ def execute_shell_command(command)
32
+ %x[#{command}]
33
+ end
34
+
35
+ def execute_service_control_command(service_control_command)
36
+ logon # required to authenticate
37
+ result = execute_shell_command(service_control_command)
38
+
39
+ extract_error_code_from_results(result) if result.upcase.include? "FAILED"
40
+ return result if service_control_command.include? 'query'
41
+ end
42
+
43
+ def remove_tabs_from_string(result)
44
+ result.gsub("\t", "")
45
+ end
46
+
47
+ def extract_error_code_from_results(result)
48
+ raise ServiceErrors::Errors.error_from_code(result).error
49
+ end
50
+
51
+ def service_control_for(command)
52
+ "sc \\\\#{@host} #{command.to_s} #{@name}"
53
+ end
54
+
55
+ def login_command
56
+ #net use \\ADDRESS\IPC$ PASSWORD /user:USERWITHDOMAIN
57
+ "net use \\\\#{@host}\\IPC$ #{@password} /user:#{@host}\\#{@user}"
58
+ end
59
+
60
+ def logon
61
+ result = %x[#{login_command}].gsub("\n", "")
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.configure do |config|
4
+ if Config::CONFIG['host_os'] =~ /darwin/
5
+ config.filter_run_excluding :windows => true
6
+ end
7
+ end
8
+
9
+ describe Win::ServiceController do
10
+ describe "when module is loaded on Windows", :windows => true do
11
+ let(:service) { double('service')}
12
+
13
+ it "should extend the WindowsService module when on Windows platform" do
14
+ service.should_receive(:send).with(:include, Win::ServiceController::WindowsService)
15
+ Win::ServiceController.included(service)
16
+ end
17
+ end
18
+
19
+ describe "when module is loaded on UNIX", :unix => true do
20
+ let(:service) { double('service')}
21
+ it "should extend the UnixService module when on the OS X platform" do
22
+ service.should_receive(:send).with(:include, Win::ServiceController::UnixService)
23
+ Win::ServiceController.included(service)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ describe Win::Service do
4
+ before do
5
+ @remote_service = Win::Service.new("W3SVC", "10.30.0.62", "Administrator", "passpass00")
6
+ end
7
+
8
+ it "should give the status of running when the service has been started" do
9
+ @remote_service.stub!(:service_status).and_return("running")
10
+ @remote_service.status.should == "running"
11
+ end
12
+
13
+ it "should confirm that the service has been started" do
14
+ @remote_service.stub!(:start_service).and_return(true)
15
+ @remote_service.start.should be_true
16
+ end
17
+
18
+ it "should give an error if the service was already started when starting" do
19
+ @remote_service.stub!(:start_service).and_return(Win::ServiceErrors::Errors.error_from_code("0x00000420").error)
20
+ @remote_service.start.should == "An instance of the service is already running."
21
+ end
22
+
23
+ it "should give the status of running when the service has been stopped" do
24
+ @remote_service.stub!(:service_status).and_return("stopped")
25
+ @remote_service.status.should == "stopped"
26
+ end
27
+
28
+ it "should give an error if the service was already stopped when stopping" do
29
+ @remote_service.stub!(:stop_service).and_return(Win::ServiceErrors::Errors.error_from_code("0x00000426").error)
30
+ @remote_service.stop.should == "The service has not been started."
31
+ end
32
+
33
+ it "should confirm that the service has been stopped" do
34
+ @remote_service.stub!(:stop_service).and_return(true)
35
+ @remote_service.stop.should be_true
36
+ end
37
+
38
+ it "should give the status of pending when the service is being stopped" do
39
+ @remote_service.stub!(:service_status).and_return("pending")
40
+ @remote_service.status.should == "pending"
41
+ end
42
+
43
+ it "should confirm that the service has been paused" do
44
+ @remote_service.stub!(:pause_service).and_return(true)
45
+ @remote_service.pause.should be_true
46
+ end
47
+
48
+ it "should give the status of paused when the service has been paused" do
49
+ @remote_service.stub!(:service_status).and_return("paused")
50
+ @remote_service.status.should == "paused"
51
+ end
52
+
53
+ it "should confirm that the service has been resumed" do
54
+ @remote_service.stub!(:resume_service).and_return(true)
55
+ @remote_service.resume.should be_true
56
+ end
57
+
58
+ it "should give the status of started when the service has been resumed" do
59
+ @remote_service.stub!(:service_status).and_return("running")
60
+ @remote_service.status.should == "running"
61
+ end
62
+ end
@@ -0,0 +1,5 @@
1
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '../lib')
2
+
3
+ require "rspec"
4
+ require "rbconfig"
5
+ require "win/service"
@@ -0,0 +1,157 @@
1
+ require "rspec"
2
+
3
+ RSpec.configure do |config|
4
+ if Config::CONFIG['host_os'] =~ /mingw32/
5
+ config.filter_run_excluding :unix => true
6
+ end
7
+ end
8
+
9
+ describe Win::ServiceController::UnixService, :unix => true do
10
+
11
+ describe "when service status is being requested" do
12
+ let(:service) {Win::Service.new('Service', '127.0.0.1', 'admin', 'password')}
13
+ let(:stdout) {double('stdout')}
14
+ let(:stderr) {double('stderr')}
15
+ let(:stdin) {double('stdin')}
16
+
17
+ it "should successfully return running when the service is started" do
18
+ service.should_receive(:send).with(:include, Win::ServiceController::UnixService)
19
+
20
+ stdout.should_receive(:read).and_return("W3SVC service is running.\nConfiguration details:\n\tControls Accepted = 0x7\n\tService Type = 0x20\n\tStart Type = 0x2\n\tError Control = 0x1\n\tTag ID = 0x0\n\tExecutable Path = C:\\WINDOWS\\System32\\svchost.exe -k iissvcs\n\tLoad Order Group = \n\tDependencies = RPCSS/HTTPFilter/IISADMIN/\n\tStart Name = LocalSystem\n\tDisplay Name = World Wide Web Publishing Service\n")
21
+ stderr.should_receive(:read).and_return('')
22
+
23
+ Win::ServiceController.included(service)
24
+ Open3.stub!(:popen3).and_return([stdin, stdout, stderr])
25
+ service.status.should == "running"
26
+ end
27
+
28
+ it "should successfully return stopped when the service is stopped" do
29
+ service.should_receive(:send).with(:include, Win::ServiceController::UnixService)
30
+
31
+ stdout.should_receive(:read).and_return("W3SVC service is stopped.\nConfiguration details:\n\tControls Accepted = 0x0\n\tService Type = 0x20\n\tStart Type = 0x2\n\tError Control = 0x1\n\tTag ID = 0x0\n\tExecutable Path = C:\\WINDOWS\\System32\\svchost.exe -k iissvcs\n\tLoad Order Group = \n\tDependencies = RPCSS/HTTPFilter/IISADMIN/\n\tStart Name = LocalSystem\n\tDisplay Name = World Wide Web Publishing Service\n")
32
+ stderr.should_receive(:read).and_return('')
33
+
34
+ Win::ServiceController.included(service)
35
+ Open3.stub!(:popen3).and_return([stdin, stdout, stderr])
36
+ service.status.should == "stopped"
37
+ end
38
+
39
+ it "should successfully return pending when the service is stopping" do
40
+ service.should_receive(:send).with(:include, Win::ServiceController::UnixService)
41
+
42
+ stdout.should_receive(:read).and_return("W3SVC service is stop pending.\nConfiguration details:\n\tControls Accepted = 0x5\n\tService Type = 0x10\n\tStart Type = 0x3\n\tError Control = 0x1\n\tTag ID = 0x0\n\tExecutable Path = \"C:\\Program Files\\Virtual Hold Technology\\VHT_QueueManager_Service.exe\"\n\tLoad Order Group = \n\tDependencies = /\n\tStart Name = LocalSystem\n\tDisplay Name = VHT_QueueManager\n")
43
+ stderr.should_receive(:read).and_return('')
44
+
45
+ Win::ServiceController.included(service)
46
+ Open3.stub!(:popen3).and_return([stdin, stdout, stderr])
47
+ service.status.should == "pending"
48
+ end
49
+
50
+ it "should successfully return paused when the service is paused" do
51
+ service.should_receive(:send).with(:include, Win::ServiceController::UnixService)
52
+
53
+ stdout.should_receive(:read).and_return("W3SVC service is paused.\nConfiguration details:\n\tControls Accepted = 0x7\n\tService Type = 0x20\n\tStart Type = 0x2\n\tError Control = 0x1\n\tTag ID = 0x0\n\tExecutable Path = C:\\WINDOWS\\System32\\svchost.exe -k iissvcs\n\tLoad Order Group = \n\tDependencies = RPCSS/HTTPFilter/IISADMIN/\n\tStart Name = LocalSystem\n\tDisplay Name = World Wide Web Publishing Service\n")
54
+ stderr.should_receive(:read).and_return('')
55
+
56
+ Win::ServiceController.included(service)
57
+ Open3.stub!(:popen3).and_return([stdin, stdout, stderr])
58
+ service.status.should == "paused"
59
+ end
60
+ end
61
+
62
+ describe "when service is being controlled" do
63
+ let(:service) {Win::Service.new('Service', '127.0.0.1', 'admin', 'password')}
64
+ let(:stdout) {double('stdout')}
65
+ let(:stderr) {double('stderr')}
66
+ let(:stdin) {double('stdin')}
67
+
68
+ it "should successfully start a stopped service" do
69
+ service.should_receive(:send).with(:include, Win::ServiceController::UnixService)
70
+
71
+ stdout.should_receive(:read).and_return('..\nSuccessfully started service: VHT_QueueManager\n')
72
+ stderr.should_receive(:read).and_return('')
73
+
74
+ Win::ServiceController.included(service)
75
+ Open3.stub!(:popen3).and_return([stdin, stdout, stderr])
76
+ expect { service.start }.should_not raise_error
77
+ end
78
+
79
+ it "should successfully stop a started service" do
80
+ service.should_receive(:send).with(:include, Win::ServiceController::UnixService)
81
+
82
+ stdout.should_receive(:read).and_return('..............................\nVHT_QueueManager service is stop pending.\n')
83
+ stderr.should_receive(:read).and_return('')
84
+
85
+ Win::ServiceController.included(service)
86
+ Open3.stub!(:popen3).and_return([stdin, stdout, stderr])
87
+ expect { service.stop }.should_not raise_error
88
+ end
89
+
90
+ it "should successfully pause a started service" do
91
+ service.should_receive(:send).with(:include, Win::ServiceController::UnixService)
92
+
93
+ stdout.should_receive(:read).and_return('service pause W3SVC\n.\nW3SVC service is paused.')
94
+ stderr.should_receive(:read).and_return('')
95
+
96
+ Win::ServiceController.included(service)
97
+ Open3.stub!(:popen3).and_return([stdin, stdout, stderr])
98
+ expect { service.pause }.should_not raise_error
99
+ end
100
+
101
+ it "should successfully resume a paused service" do
102
+ service.should_receive(:send).with(:include, Win::ServiceController::UnixService)
103
+
104
+ stdout.should_receive(:read).and_return('service resume W3SVC\n.\nW3SVC service is running.')
105
+ stderr.should_receive(:read).and_return('')
106
+
107
+ Win::ServiceController.included(service)
108
+ Open3.stub!(:popen3).and_return([stdin, stdout, stderr])
109
+ expect { service.resume }.should_not raise_error
110
+ end
111
+
112
+ it "should raise an error when trying to stop an already stopped service" do
113
+ service.should_receive(:send).with(:include, Win::ServiceController::UnixService)
114
+
115
+ stdout.should_receive(:read).and_return('')
116
+ stderr.should_receive(:read).and_return('Control service request failed. [DOS code 0x00000426]')
117
+
118
+ Win::ServiceController.included(service)
119
+ Open3.stub!(:popen3).and_return([stdin, stdout, stderr])
120
+ expect { service.stop }.should raise_error
121
+ end
122
+
123
+ it "should raise an error when trying to start an already started service" do
124
+ service.should_receive(:send).with(:include, Win::ServiceController::UnixService)
125
+
126
+ stdout.should_receive(:read).and_return('')
127
+ stderr.should_receive(:read).and_return('Query status request failed. [DOS code 0x00000420]')
128
+
129
+ Win::ServiceController.included(service)
130
+ Open3.stub!(:popen3).and_return([stdin, stdout, stderr])
131
+ expect { service.stop }.should raise_error
132
+ end
133
+
134
+ it "should raise an error when trying to pause an already stopped service" do
135
+ service.should_receive(:send).with(:include, Win::ServiceController::UnixService)
136
+
137
+ stdout.should_receive(:read).and_return('')
138
+ stderr.should_receive(:read).and_return('Control service request failed. [DOS code 0x00000426]')
139
+
140
+ Win::ServiceController.included(service)
141
+ Open3.stub!(:popen3).and_return([stdin, stdout, stderr])
142
+ expect { service.pause }.should raise_error
143
+ end
144
+
145
+ it "should raise an error when trying to resume an already stopped service" do
146
+ service.should_receive(:send).with(:include, Win::ServiceController::UnixService)
147
+
148
+ stdout.should_receive(:read).and_return('')
149
+ stderr.should_receive(:read).and_return('Control service request failed. [DOS code 0x00000426]')
150
+
151
+ Win::ServiceController.included(service)
152
+ Open3.stub!(:popen3).and_return([stdin, stdout, stderr])
153
+ expect { service.resume }.should raise_error
154
+ end
155
+
156
+ end
157
+ end
@@ -0,0 +1,121 @@
1
+ require "rspec"
2
+
3
+ RSpec.configure do |config|
4
+ if Config::CONFIG['host_os'] =~ /darwin/
5
+ config.filter_run_excluding :windows => true
6
+ end
7
+ end
8
+
9
+ describe Win::ServiceController::WindowsService, :windows => true do
10
+ describe "when service status is being requested" do
11
+ let(:service) {Win::Service.new('Service', '127.0.0.1', 'admin', 'password')}
12
+
13
+ it "should successfully return running when the service is started" do
14
+ service.should_receive(:send).with(:include, Win::ServiceController::WindowsService)
15
+ Win::ServiceController.included(service)
16
+ service.stub!(:logon).and_return("")
17
+ service.stub!(:execute_shell_command).and_return("\nSERVICE_NAME: W3SVC\n\t\tTYPE : 20 WIN32_SHARE_PROCESS\n\t\tSTATE : 4 RUNNING\n\t\t\t\t\t\t\t\t(STOPPABLE, NOT_PAUSABLE, ACCEPTS_SHUTDOWN)\n\t\tWIN32_EXIT_CODE : 0 (0x0)\n\t\tSERVICE_EXIT_CODE : 0 (0x0)\n\t\tCHECKPOINT : 0x0\n\t\tWAIT_HINT : 0x0\n")
18
+ service.status.should == "running"
19
+ end
20
+
21
+ it "should successfully return stopped when the service is stopped" do
22
+ service.should_receive(:send).with(:include, Win::ServiceController::WindowsService)
23
+ Win::ServiceController.included(service)
24
+ service.stub!(:logon).and_return("")
25
+ service.stub!(:execute_shell_command).and_return("\nSERVICE_NAME: W3SVC\n\t\tTYPE : 20 WIN32_SHARE_PROCESS\n\t\tSTATE : 1 STOPPED\n\t\t\t\t\t\t\t\t(STOPPABLE, NOT_PAUSABLE, ACCEPTS_SHUTDOWN)\n\t\tWIN32_EXIT_CODE : 0 (0x0)\n\t\tSERVICE_EXIT_CODE : 0 (0x0)\n\t\tCHECKPOINT : 0x0\n\t\tWAIT_HINT : 0x0\n")
26
+ service.status.should == "stopped"
27
+ end
28
+
29
+ it "should successfully return pending when the service is stopping" do
30
+ service.should_receive(:send).with(:include, Win::ServiceController::WindowsService)
31
+ Win::ServiceController.included(service)
32
+ service.stub!(:logon).and_return("")
33
+ service.stub!(:execute_shell_command).and_return("\nSERVICE_NAME: W3SVC\n\t\tTYPE : 20 WIN32_SHARE_PROCESS\n\t\tSTATE : 3 STOP_PENDING\n\t\t\t\t\t\t\t\t(NOT_STOPPABLE, NOT_PAUSABLE, IGNORESs_SHUTDOWN)\n\t\tWIN32_EXIT_CODE : 0 (0x0)\n\t\tSERVICE_EXIT_CODE : 0 (0x0)\n\t\tCHECKPOINT : 0x0\n\t\tWAIT_HINT : 0x0\n")
34
+ service.status.should == "pending"
35
+ end
36
+
37
+ it "should successfully return paused when the service is paused" do
38
+ service.should_receive(:send).with(:include, Win::ServiceController::WindowsService)
39
+ Win::ServiceController.included(service)
40
+ service.stub!(:logon).and_return("")
41
+ service.stub!(:execute_shell_command).and_return("\nSERVICE_NAME: W3SVC\n\t\tTYPE : 20 WIN32_SHARE_PROCESS\n\t\tSTATE : 7 PAUSED\n\t\t\t\t\t\t\t\t(NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)\n\t\tWIN32_EXIT_CODE : 0 (0x0)\n\t\tSERVICE_EXIT_CODE : 0 (0x0)\n\t\tCHECKPOINT : 0x0\n\t\tWAIT_HINT : 0x0\n")
42
+ service.status.should == "paused"
43
+ end
44
+ end
45
+
46
+ describe "when service is being controlled" do
47
+ let(:service) {Win::Service.new('Service', '127.0.0.1', 'admin', 'password')}
48
+
49
+ it "should successfully start a stopped service" do
50
+ service.should_receive(:send).with(:include, Win::ServiceController::WindowsService)
51
+ Win::ServiceController.included(service)
52
+ service.stub!(:logon).and_return("")
53
+ service.stub!(:execute_shell_command).and_return("\nSERVICE_NAME: W3SVC\n\t\tTYPE : 20 WIN32_SHARE_PROCESS\n\t\tSTATE : 2 START_PENDING\n\t\t\t\t\t\t\t\t(NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)\n\t\tWIN32_EXIT_CODE : 0 (0x0)\n\t\tSERVICE_EXIT_CODE : 0 (0x0)\n\t\tCHECKPOINT : 0x0\n\t\tWAIT_HINT : 0x7d0\n\t\tPID : 632\n\t\tFLAGS :\n")
54
+ expect { service.start }.should_not raise_error
55
+ end
56
+
57
+ it "should successfully stop a started service" do
58
+ service.should_receive(:send).with(:include, Win::ServiceController::WindowsService)
59
+ Win::ServiceController.included(service)
60
+ service.stub!(:logon).and_return("")
61
+ service.stub!(:execute_shell_command).and_return("\nSERVICE_NAME: W3SVC\n\t\tTYPE : 20 WIN32_SHARE_PROCESS\n\t\tSTATE : 3 STOP_PENDING\n\t\t\t\t\t\t\t\t(NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)\n\t\tWIN32_EXIT_CODE : 0 (0x0)\n\t\tSERVICE_EXIT_CODE : 0 (0x0)\n\t\tCHECKPOINT : 0x1\n\t\tWAIT_HINT : 0x4e20\n")
62
+ expect { service.stop }.should_not raise_error
63
+ end
64
+
65
+ it "should successfully pause a started service" do
66
+ service.should_receive(:send).with(:include, Win::ServiceController::WindowsService)
67
+ Win::ServiceController.included(service)
68
+ service.stub!(:logon).and_return("")
69
+ service.stub!(:execute_shell_command).and_return("\nSERVICE_NAME: W3SVC\n\t\tTYPE : 20 WIN32_SHARE_PROCESS\n\t\tSTATE : 6 PAUSE_PENDING\n\t\t\t\t\t\t\t\t(NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)\n\t\tWIN32_EXIT_CODE : 0 (0x0)\n\t\tSERVICE_EXIT_CODE : 0 (0x0)\n\t\tCHECKPOINT : 0x1\n\t\tWAIT_HINT : 0x4e20\n")
70
+ expect { service.pause }.should_not raise_error
71
+ end
72
+
73
+ it "should successfully resume a paused service" do
74
+ service.should_receive(:send).with(:include, Win::ServiceController::WindowsService)
75
+ Win::ServiceController.included(service)
76
+ service.stub!(:logon).and_return("")
77
+ service.stub!(:execute_shell_command).and_return("\nSERVICE_NAME: W3SVC\n\t\tTYPE : 20 WIN32_SHARE_PROCESS\n\t\tSTATE : 5 CONTINUE_PENDING\n\t\t\t\t\t\t\t\t(NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)\n\t\tWIN32_EXIT_CODE : 0 (0x0)\n\t\tSERVICE_EXIT_CODE : 0 (0x0)\n\t\tCHECKPOINT : 0x1\n\t\tWAIT_HINT : 0x4e20\n")
78
+ expect { service.resume }.should_not raise_error
79
+ end
80
+
81
+ it "should raise an error when trying to stop an already stopped service" do
82
+ service.should_receive(:send).with(:include, Win::ServiceController::WindowsService)
83
+ Win::ServiceController.included(service)
84
+ service.stub!(:logon).and_return("")
85
+ service.stub!(:execute_shell_command).and_return("[SC] ControlService FAILED 1061:\n\nThe service cannot accept control messages at this time.")
86
+ expect { service.stop }.should raise_error
87
+ end
88
+
89
+ it "should raise an error when trying to start an already started service" do
90
+ service.should_receive(:send).with(:include, Win::ServiceController::WindowsService)
91
+ Win::ServiceController.included(service)
92
+ service.stub!(:logon).and_return("")
93
+ service.stub!(:execute_shell_command).and_return("[SC] ControlService FAILED 1056:\n\nAn instance of the service is already running.")
94
+ expect { service.start }.should raise_error
95
+ end
96
+
97
+ it "should raise an error when trying to start an already started service" do
98
+ service.should_receive(:send).with(:include, Win::ServiceController::WindowsService)
99
+ Win::ServiceController.included(service)
100
+ service.stub!(:logon).and_return("")
101
+ service.stub!(:execute_shell_command).and_return("[SC] ControlService FAILED 1056:\n\nAn instance of the service is already running.")
102
+ expect { service.start }.should raise_error
103
+ end
104
+
105
+ it "should raise an error when trying to pause an already stopped service" do
106
+ service.should_receive(:send).with(:include, Win::ServiceController::WindowsService)
107
+ Win::ServiceController.included(service)
108
+ service.stub!(:logon).and_return("")
109
+ service.stub!(:execute_shell_command).and_return("[SC] ControlService FAILED 1062:\n\nAn instance of the service is already running.")
110
+ expect { service.pause }.should raise_error
111
+ end
112
+
113
+ it "should raise an error when trying to resume an already stopped service" do
114
+ service.should_receive(:send).with(:include, Win::ServiceController::WindowsService)
115
+ Win::ServiceController.included(service)
116
+ service.stub!(:logon).and_return("")
117
+ service.stub!(:execute_shell_command).and_return("[SC] ControlService FAILED 1062:\n\nAn instance of the service is already running.")
118
+ expect { service.resume }.should raise_error
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,5 @@
1
+ require "test/unit"
2
+ require "win-service"
3
+
4
+ class TestWinService < Test::Unit::TestCase
5
+ end
@@ -0,0 +1,34 @@
1
+ require 'rubygems'
2
+
3
+ spec = Gem::Specification.new do |gem|
4
+ gem.name = 'win-service'
5
+ gem.version = '0.1.0'
6
+ gem.authors = ['James T. Pavlic']
7
+ gem.email = 'james_pavlic@hotmail.com'
8
+ gem.license = 'The MIT License'
9
+ gem.homepage = 'https://github.com/jpavlic/win-service'
10
+ gem.platform = Gem::Platform::RUBY
11
+ gem.summary = 'An interface for MS Windows services'
12
+ gem.add_development_dependency('rspec')
13
+ gem.has_rdoc = true
14
+
15
+ gem.extra_rdoc_files = [
16
+ 'History.txt',
17
+ 'README.txt',
18
+ 'Manifest.txt',
19
+ 'doc/service.rdoc'
20
+ ]
21
+
22
+ gem.rubyforge_project = 'win-service'
23
+ gem.required_ruby_version = '>= 1.8.7'
24
+
25
+ gem.description = <<-EOF
26
+ A ruby gem that will allow the basic functions of getting the status,
27
+ stopping and starting of a windows service from both a windows and a mac os x operating system.
28
+ EOF
29
+ end
30
+
31
+ if $PROGRAM_NAME == __FILE__
32
+ Gem.manage_gems if Gem::RubyGemsVersion.to_f < 1.0
33
+ Gem::Builder.new(spec).build
34
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: win-service
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - James T. Pavlic
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-05-05 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: hoe
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 35
29
+ segments:
30
+ - 2
31
+ - 9
32
+ - 4
33
+ version: 2.9.4
34
+ type: :development
35
+ version_requirements: *id001
36
+ description: " A ruby gem that will allow the basic functions of getting the status,\n stopping and starting of a windows service from both a windows and a mac os x operating system.\n"
37
+ email: james_pavlic@hotmail.com
38
+ executables: []
39
+
40
+ extensions: []
41
+
42
+ extra_rdoc_files:
43
+ - Manifest.txt
44
+ - History.txt
45
+ - README.txt
46
+ files:
47
+ - Manifest.txt
48
+ - History.txt
49
+ - README.txt
50
+ - Rakefile
51
+ - win-service.gemspec
52
+ - lib/win/service.rb
53
+ - lib/win/service_controller.rb
54
+ - lib/win/service_controller/service_controller.rb
55
+ - lib/win/service_controller/service_errors.rb
56
+ - lib/win/service_controller/unix_service.rb
57
+ - lib/win/service_controller/windows_service.rb
58
+ - spec/service_controller_spec.rb
59
+ - spec/service_spec.rb
60
+ - spec/spec_helper.rb
61
+ - spec/unix_service_spec.rb
62
+ - spec/windows_service_spec.rb
63
+ - test/test_win_service.rb
64
+ - .gemtest
65
+ homepage: http://codinghappy.blogspot.com/
66
+ licenses: []
67
+
68
+ post_install_message:
69
+ rdoc_options:
70
+ - --main
71
+ - README.txt
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ hash: 3
80
+ segments:
81
+ - 0
82
+ version: "0"
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ hash: 3
89
+ segments:
90
+ - 0
91
+ version: "0"
92
+ requirements: []
93
+
94
+ rubyforge_project: win-service
95
+ rubygems_version: 1.8.0
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: An interface for MS Windows services
99
+ test_files:
100
+ - test/test_win_service.rb