http_server_manager 0.0.1

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.
@@ -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