http_server_manager 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,30 @@
1
+ require 'rake/tasklib' unless defined? (::Rake::TaskLib)
2
+
3
+ module HttpServerManager
4
+
5
+ module Rake
6
+
7
+ class ServerTasks < ::Rake::TaskLib
8
+
9
+ def initialize(server)
10
+ desc "Starts a #{server.name} as a background process"
11
+ task :start do
12
+ server.start!
13
+ end
14
+
15
+ desc "Stops a running #{server.name}"
16
+ task :stop do
17
+ server.stop!
18
+ end
19
+
20
+ desc "Displays the status of a #{server.name} process"
21
+ task :status do
22
+ puts "#{server.name} is #{server.status}"
23
+ end
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+
30
+ end
@@ -0,0 +1,3 @@
1
+ require 'rake'
2
+
3
+ require_relative 'server_tasks'
@@ -0,0 +1,83 @@
1
+ module HttpServerManager
2
+
3
+ class Server
4
+
5
+ attr_reader :name, :port
6
+
7
+ def initialize(options)
8
+ @name = options[:name]
9
+ @port = options[:port]
10
+ @deletable_artifacts = [pid_file_path]
11
+ end
12
+
13
+ def start!
14
+ if running?
15
+ logger.info "#{@name} already running on port #{@port}"
16
+ else
17
+ ensure_directories_exist
18
+ pid = Process.spawn(start_command, { [:out, :err] => [log_file_path, "w"] })
19
+ create_pid_file(pid)
20
+ Wait.until_true!("#{@name} is running") { running? }
21
+ logger.info "#{@name} started on port #{@port}"
22
+ end
23
+ end
24
+
25
+ def stop!
26
+ if running?
27
+ Process.kill_tree(9, current_pid)
28
+ FileUtils.rm_f(@deletable_artifacts)
29
+ logger.info "#{@name} stopped"
30
+ else
31
+ logger.info "#{@name} not running"
32
+ end
33
+ end
34
+
35
+ def status
36
+ running? ? :started : :stopped
37
+ end
38
+
39
+ def to_s
40
+ "#{@name} on port #{@port}"
41
+ end
42
+
43
+ private
44
+
45
+ def running?
46
+ !!Net::HTTP.get_response("localhost", "/", @port) rescue false
47
+ end
48
+
49
+ def current_pid
50
+ File.exists?(pid_file_path) ? File.read(pid_file_path).to_i : nil
51
+ end
52
+
53
+ def pid_file_path
54
+ File.join(pid_dir, "#{@name}.pid")
55
+ end
56
+
57
+ def create_pid_file(pid)
58
+ File.open(pid_file_path, "w") { |file| file.write(pid) }
59
+ end
60
+
61
+ def log_file_path
62
+ File.join(log_dir, "#{@name}_console.log")
63
+ end
64
+
65
+ def ensure_directories_exist
66
+ FileUtils.mkdir_p([pid_dir, log_dir])
67
+ end
68
+
69
+ def pid_dir
70
+ HttpServerManager.pid_dir
71
+ end
72
+
73
+ def log_dir
74
+ HttpServerManager.log_dir
75
+ end
76
+
77
+ def logger
78
+ HttpServerManager.logger
79
+ end
80
+
81
+ end
82
+
83
+ end
@@ -0,0 +1,11 @@
1
+ module HttpServerManager
2
+
3
+ class StdOutLogger
4
+
5
+ def info(message)
6
+ puts message
7
+ end
8
+
9
+ end
10
+
11
+ end
@@ -0,0 +1,3 @@
1
+ module HttpServerManager
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,25 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.require(:default)
4
+
5
+ require 'net/http'
6
+ require 'sys/proctree'
7
+ require 'wait_until'
8
+
9
+ require_relative 'http_server_manager/stdout_logger'
10
+
11
+ module HttpServerManager
12
+
13
+ class << self
14
+
15
+ attr_accessor :logger, :pid_dir, :log_dir
16
+
17
+ def logger
18
+ @logger || HttpServerManager::StdOutLogger.new
19
+ end
20
+
21
+ end
22
+
23
+ end
24
+
25
+ require_relative 'http_server_manager/server'
@@ -0,0 +1,61 @@
1
+ describe HttpServerManager::Rake::ServerTasks do
2
+ include_context "server integration utilities"
3
+ include ::Rake::DSL
4
+
5
+ before(:all) do
6
+ namespace :rack_server do
7
+ server_tasks
8
+ end
9
+ end
10
+
11
+ describe "start task" do
12
+
13
+ let(:task) { ::Rake::Task["rack_server:start"] }
14
+
15
+ after(:each) { force_stop! }
16
+
17
+ it "should start a stopped server" do
18
+ task.execute
19
+
20
+ wait_until_started!
21
+ end
22
+
23
+ end
24
+
25
+ describe "stop task" do
26
+
27
+ let(:task) { ::Rake::Task["rack_server:stop"] }
28
+
29
+ before(:each) { force_start! }
30
+
31
+ after(:each) { force_stop! } # Ensure server has completely stopped
32
+
33
+ it "should stop a started server" do
34
+ task.execute
35
+
36
+ wait_until_stopped!
37
+ end
38
+
39
+ end
40
+
41
+ describe "status task" do
42
+
43
+ let(:task) { ::Rake::Task["rack_server:status"] }
44
+
45
+ it "should write the server name and it's status to stdout" do
46
+ server_tasks.should_receive(:puts).with("rack_server is stopped")
47
+
48
+ task.execute
49
+ end
50
+
51
+ end
52
+
53
+ def server_tasks
54
+ @server_tasks ||= HttpServerManager::Rake::ServerTasks.new(server)
55
+ end
56
+
57
+ def server
58
+ @server ||= RackServer.new(port: 4001)
59
+ end
60
+
61
+ end
@@ -0,0 +1,169 @@
1
+ describe HttpServerManager::Server do
2
+ include_context "server integration utilities"
3
+
4
+ let(:server) { RackServer.new(port: 4001) }
5
+
6
+ describe "#start!" do
7
+
8
+ after(:each) { force_stop! }
9
+
10
+ describe "when the server is not running" do
11
+
12
+ after(:each) { wait_until_started! } # Ensure server has completely started
13
+
14
+ it "should start the server via the provided command" do
15
+ server.start!
16
+
17
+ wait_until_started!
18
+ end
19
+
20
+ it "should create a pid file for the server in the configured pid directory" do
21
+ server.start!
22
+
23
+ ::Wait.until_true!("rack server pid created") { pid_file_exists? }
24
+ end
25
+
26
+ it "should create a log file capturing the stdout and stderr of the server in the configured log directory" do
27
+ server.start!
28
+
29
+ ::Wait.until_true!("log file is created") do
30
+ File.exists?("#{log_dir}/rack_server_console.log")
31
+ end
32
+ end
33
+
34
+ it "should log that the server started on the configured port" do
35
+ logger.should_receive(:info).with(/started on port 4001/)
36
+
37
+ server.start!
38
+ end
39
+
40
+ end
41
+
42
+ describe "when the server is already running" do
43
+
44
+ before(:each) do
45
+ server.start!
46
+ wait_until_started!
47
+ end
48
+
49
+ it "should log that the server is already running on the configured port" do
50
+ logger.should_receive(:info).with(/already running on port 4001/)
51
+
52
+ server.start!
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+
59
+ describe "#stop!" do
60
+
61
+ describe "when the server is running" do
62
+
63
+ before(:each) { force_start! }
64
+
65
+ after(:each) { force_stop! } # Ensure server has completely stopped
66
+
67
+ it "should stop the server" do
68
+ server.stop!
69
+
70
+ wait_until_stopped!
71
+ end
72
+
73
+ it "should delete the servers pid file" do
74
+ server.stop!
75
+
76
+ ::Wait.until_false!("rack server pid is deleted") do
77
+ File.exists?("#{pid_dir}/rack_server.pid")
78
+ end
79
+ end
80
+
81
+ it "should log that the server has stopped" do
82
+ logger.should_receive(:info).with(/stopped/)
83
+
84
+ server.stop!
85
+ end
86
+
87
+ end
88
+
89
+ describe "when the server is not running" do
90
+
91
+ it "should log that the server is not running" do
92
+ logger.should_receive(:info).with(/not running/)
93
+
94
+ server.stop!
95
+ end
96
+
97
+ end
98
+
99
+ end
100
+
101
+ describe "#status" do
102
+
103
+ describe "when the server is running" do
104
+
105
+ before(:each) { force_start! }
106
+
107
+ after(:each) { force_stop! }
108
+
109
+ describe "and the pid file exists" do
110
+
111
+ it "should return :started" do
112
+ server.status.should eql(:started)
113
+ end
114
+
115
+ end
116
+
117
+ describe "and the pid file does not exist" do
118
+
119
+ before(:each) { force_pid_file_deletion! }
120
+
121
+ after(:each) { restore_pid_file! }
122
+
123
+ it "should return :started" do
124
+ server.status.should eql(:started)
125
+ end
126
+
127
+ end
128
+
129
+ end
130
+
131
+ describe "when the server is not running" do
132
+
133
+ describe "and the pid file does not exist" do
134
+
135
+ it "should return :stopped" do
136
+ server.status.should eql(:stopped)
137
+ end
138
+
139
+ end
140
+
141
+ describe "and the pid file exists" do
142
+
143
+ before(:each) { force_pid_file_creation! }
144
+
145
+ after(:each) { force_pid_file_deletion! }
146
+
147
+ it "should return :stopped" do
148
+ server.status.should eql(:stopped)
149
+ end
150
+
151
+ end
152
+
153
+ end
154
+
155
+ end
156
+
157
+ describe "#to_s" do
158
+
159
+ it "should return a string containing the servers name" do
160
+ server.to_s.should match(/rack_server/)
161
+ end
162
+
163
+ it "should return a string containing the servers port" do
164
+ server.to_s.should match(/4001/)
165
+ end
166
+
167
+ end
168
+
169
+ end
@@ -0,0 +1,16 @@
1
+ describe HttpServerManager::StdOutLogger do
2
+
3
+ let(:logger) { HttpServerManager::StdOutLogger.new }
4
+
5
+ describe "#info" do
6
+
7
+ it "should write the message to stdout" do
8
+ message = "Some message"
9
+ logger.should_receive(:puts).with(message)
10
+
11
+ logger.info message
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,31 @@
1
+ describe HttpServerManager do
2
+
3
+ describe ".logger" do
4
+
5
+ describe "when no logger has been explicitly configured" do
6
+
7
+ before(:each) { HttpServerManager.logger = nil }
8
+
9
+ it "should default to the stdout logger" do
10
+ HttpServerManager.logger.should be_a(HttpServerManager::StdOutLogger)
11
+ end
12
+
13
+ end
14
+
15
+ describe "when a logger has been explicitly configured" do
16
+
17
+ let(:logger) { double("Logger").as_null_object }
18
+
19
+ before(:each) { HttpServerManager.logger = logger }
20
+
21
+ after(:each) { HttpServerManager.logger = nil }
22
+
23
+ it "should return the configured logger" do
24
+ HttpServerManager.logger.should eql(logger)
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,28 @@
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_filter "/spec/"
4
+ minimum_coverage 100
5
+ refuse_coverage_drop
6
+ end if ENV["coverage"]
7
+
8
+ require_relative '../lib/http_server_manager'
9
+ require_relative '../lib/http_server_manager/rake/task_generators'
10
+
11
+ module HttpServerManager
12
+
13
+ def self.root
14
+ @root ||= File.expand_path("../../../", __FILE__)
15
+ end
16
+
17
+ end
18
+
19
+ require_relative 'support/http_server_manager/test/silent_logger'
20
+ HttpServerManager.logger = HttpServerManager::Test::SilentLogger
21
+ HttpServerManager.pid_dir = "#{HttpServerManager.root}/tmp/pids"
22
+ HttpServerManager.log_dir = "#{HttpServerManager.root}/tmp/logs"
23
+
24
+ Bundler.require(:test)
25
+
26
+ require_relative '../examples/rack_server'
27
+
28
+ Dir[File.expand_path('../support/**/*.rb', __FILE__)].each { |file| require file }
@@ -0,0 +1,99 @@
1
+ module HttpServerManager
2
+
3
+ module Test
4
+
5
+ module ServerIntegrationUtilities
6
+
7
+ def force_start!
8
+ server.start!
9
+ wait_until_started!
10
+ end
11
+
12
+ alias_method :force_server_start!, :force_start!
13
+
14
+ def force_stop!
15
+ server.stop!
16
+ wait_until_stopped!
17
+ end
18
+
19
+ alias_method :force_server_stop!, :force_stop!
20
+
21
+ def force_pid_file_creation!
22
+ File.open(pid_file_path, "w") { |file| file.write "0" }
23
+ wait_until_file_exists!(pid_file_path)
24
+ end
25
+
26
+ def force_pid_file_deletion!
27
+ FileUtils.rm_f(pid_file_path)
28
+ ::Wait.until_false!("#{pid_file_path} is deleted") { pid_file_exists? }
29
+ end
30
+
31
+ def restore_pid_file!
32
+ FileUtils.cp(pid_file_backup_path, pid_file_path)
33
+ wait_until_file_exists!(pid_file_path)
34
+ end
35
+
36
+ def wait_until_started!
37
+ ::Wait.until_true!("#{server.name} starts") do
38
+ !!Net::HTTP.get_response("localhost", "/", server.port) && pid_file_exists?
39
+ end
40
+ FileUtils.cp(pid_file_path, pid_file_backup_path)
41
+ end
42
+
43
+ def wait_until_stopped!
44
+ ::Wait.until_true!("#{server.name} stops") do
45
+ begin
46
+ Net::HTTP.get_response("localhost", "/", server.port)
47
+ false
48
+ rescue
49
+ !pid_file_exists?
50
+ end
51
+ end
52
+ end
53
+
54
+ def wait_until_file_exists!(file)
55
+ ::Wait.until_true!("#{file} exists") { File.exists?(file) }
56
+ end
57
+
58
+ def ensure_pid_file_backup_directory_exists!
59
+ FileUtils.mkdir_p(pid_file_backup_directory)
60
+ wait_until_file_exists!(pid_file_backup_directory)
61
+ end
62
+
63
+ def pid_file_exists?
64
+ File.exists?(pid_file_path)
65
+ end
66
+
67
+ def pid_file_path
68
+ "#{pid_dir}/#{pid_file_name}"
69
+ end
70
+
71
+ def pid_file_name
72
+ "#{server.name}.pid"
73
+ end
74
+
75
+ def pid_file_backup_directory
76
+ "#{pid_dir}/backup"
77
+ end
78
+
79
+ def pid_file_backup_path
80
+ "#{pid_file_backup_directory}/#{pid_file_name}"
81
+ end
82
+
83
+ def pid_dir
84
+ HttpServerManager.pid_dir
85
+ end
86
+
87
+ def logger
88
+ HttpServerManager.logger
89
+ end
90
+
91
+ def log_dir
92
+ HttpServerManager.log_dir
93
+ end
94
+
95
+ end
96
+
97
+ end
98
+
99
+ end
@@ -0,0 +1,10 @@
1
+ shared_context "server integration utilities" do
2
+ include HttpServerManager::Test::ServerIntegrationUtilities
3
+
4
+ before(:each) do
5
+ HttpServerManager.logger.stub!(:info)
6
+
7
+ ensure_pid_file_backup_directory_exists!
8
+ end
9
+
10
+ end
@@ -0,0 +1,15 @@
1
+ module HttpServerManager
2
+
3
+ module Test
4
+
5
+ class SilentLogger
6
+
7
+ def method_missing(*args)
8
+ # Intentionally blank
9
+ end
10
+
11
+ end
12
+
13
+ end
14
+
15
+ end
metadata ADDED
@@ -0,0 +1,199 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: http_server_manager
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Matthew Ueckerman
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 10.0.3
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 10.0.3
30
+ - !ruby/object:Gem::Dependency
31
+ name: sys-proctree
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.0.4
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.0.4
46
+ - !ruby/object:Gem::Dependency
47
+ name: wait_until
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 0.0.1
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.0.1
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '2.12'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '2.12'
78
+ - !ruby/object:Gem::Dependency
79
+ name: simplecov
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: 0.7.1
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: 0.7.1
94
+ - !ruby/object:Gem::Dependency
95
+ name: flog
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: 3.2.2
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: 3.2.2
110
+ - !ruby/object:Gem::Dependency
111
+ name: travis-lint
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: 1.6.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ~>
124
+ - !ruby/object:Gem::Version
125
+ version: 1.6.0
126
+ - !ruby/object:Gem::Dependency
127
+ name: rack
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ~>
132
+ - !ruby/object:Gem::Version
133
+ version: 1.5.2
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ~>
140
+ - !ruby/object:Gem::Version
141
+ version: 1.5.2
142
+ description: Manages the lifecycle of HTTP server processes
143
+ email: matthew.ueckerman@myob.com
144
+ executables: []
145
+ extensions: []
146
+ extra_rdoc_files: []
147
+ files:
148
+ - ./lib/http_server_manager/rake/server_tasks.rb
149
+ - ./lib/http_server_manager/rake/task_generators.rb
150
+ - ./lib/http_server_manager/server.rb
151
+ - ./lib/http_server_manager/stdout_logger.rb
152
+ - ./lib/http_server_manager/version.rb
153
+ - ./lib/http_server_manager.rb
154
+ - ./spec/lib/http_server_manager/rake/server_tasks_integration_spec.rb
155
+ - ./spec/lib/http_server_manager/server_integration_spec.rb
156
+ - ./spec/lib/http_server_manager/stdout_logger_spec.rb
157
+ - ./spec/lib/http_server_manager_spec.rb
158
+ - ./spec/spec_helper.rb
159
+ - ./spec/support/http_server_manager/test/server_integration_utilities.rb
160
+ - ./spec/support/http_server_manager/test/server_integration_utilities_spec_context.rb
161
+ - ./spec/support/http_server_manager/test/silent_logger.rb
162
+ homepage: http://github.com/MYOB-Technology/http_server_manager
163
+ licenses:
164
+ - MIT
165
+ post_install_message:
166
+ rdoc_options: []
167
+ require_paths:
168
+ - lib
169
+ - spec/support
170
+ required_ruby_version: !ruby/object:Gem::Requirement
171
+ none: false
172
+ requirements:
173
+ - - ! '>='
174
+ - !ruby/object:Gem::Version
175
+ version: 1.9.3
176
+ required_rubygems_version: !ruby/object:Gem::Requirement
177
+ none: false
178
+ requirements:
179
+ - - ! '>='
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ segments:
183
+ - 0
184
+ hash: 3855735617667382002
185
+ requirements: []
186
+ rubyforge_project: http_server_manager
187
+ rubygems_version: 1.8.25
188
+ signing_key:
189
+ specification_version: 3
190
+ summary: Manages the lifecycle of HTTP server processes
191
+ test_files:
192
+ - ./spec/lib/http_server_manager/rake/server_tasks_integration_spec.rb
193
+ - ./spec/lib/http_server_manager/server_integration_spec.rb
194
+ - ./spec/lib/http_server_manager/stdout_logger_spec.rb
195
+ - ./spec/lib/http_server_manager_spec.rb
196
+ - ./spec/spec_helper.rb
197
+ - ./spec/support/http_server_manager/test/server_integration_utilities.rb
198
+ - ./spec/support/http_server_manager/test/server_integration_utilities_spec_context.rb
199
+ - ./spec/support/http_server_manager/test/silent_logger.rb