win-service 0.1.0

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