oop_rails_server 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
- ---
2
- SHA1:
3
- metadata.gz: 84afb8fd45ac3c486c2a4ac5437cf49053f210e7
4
- data.tar.gz: dc945d5c3630894bf4577d74cae750af674bdf3f
5
- SHA512:
6
- metadata.gz: 513409b059ea373c7f83b9c3749b7b5205287c2c869019e434f3565ce8f68b435259e3d2515a464a6032cf480309182abb24bb3a7b366744e2fbbcfae9cfc223
7
- data.tar.gz: d3433fb5c40f94877cfb20a8aca1ee0011b50c2d9c2885b540d3db322a4e12d9e276261b07fa49a19f05c862492c5b596d4fd26abf71c60e6ed0129b53a15cdc
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 26ef5c7bd3dcc6dc6bf29ad377c4397b510193d6
4
+ data.tar.gz: 230c9d20af081ce7885dc1300d6056ccbff7fba2
5
+ SHA512:
6
+ metadata.gz: 05c44883c4416fed68f128d239059d28e05b2ccc596ab3b1364a6220144cbe1c62af9f4c5754b565baddabb6a52fba75a0297ce2a1ef6b15624b4d68c37c8577
7
+ data.tar.gz: 178c4199b58ea6e0eebb41f850be0716ecfea1df09e212785bd7adbc1650bd1c904155bd4b8c7ae13187666a0af6d1d5a2957a3dab81145eb47a4018dbf4dd77
data/CHANGES.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # `oop_rails_server` Releases
2
2
 
3
+ ## 0.0.8, 3 April 2015
4
+
5
+ * Much better error reporting if the server fails to start up.
6
+ * Add `OopRailsServer::RailsServer#setup!`, which configures everything properly but does not actually start
7
+ the out-of-process Rails server yet.
8
+ * Allow passing paths or full URIs into `OopRailsServer::RailsServer#get`, as well as passing a separate Hash
9
+ of query values.
10
+ * Move question of which templates to use out of `OopRailsServer::Helpers` and into `OopRailsServer::RailsServer`.
11
+ * Save away the actual exact versions of Rails and Ruby being used, as well as the `RUBY_ENGINE`, and allow callers
12
+ to access them easily.
13
+
3
14
  ## 0.0.7, 21 January 2015
4
15
 
5
16
  * Further fixes for the `i18n` gem version `0.7.0`.
data/README.md CHANGED
@@ -1,6 +1,28 @@
1
1
  # OopRailsServer
2
2
 
3
- TODO: Write a gem description
3
+ Rails makes it easy enough to write test code or RSpec that runs _within_ Rails. However, what’s much, much harder
4
+ is testing code (like a RubyGem) that augments Rails itself, particularly if you want that code to be compatible
5
+ with multiple versions of Rails. Often people will simply check in a full Rails tree (_i.e._, that which is generated
6
+ by `rails new`), but that fixes you to an exact version of Rails and is difficult to upgrade or manipulate.
7
+
8
+ `OopRailsServer` provides a completely different, much cleaner solution: it provides an object,
9
+ `OopRailsServer::RailsServer`. This object knows how to:
10
+
11
+ * Install any version of Rails from scratch, completely cleanly (_i.e._, the equivalent of `gem install rails -v=4.2.0`);
12
+ * Use that version of Rails to create a new Rails installation (_i.e._, `rails _4.2.0_ new`);
13
+ * Add any lines you want to the resulting Rails Gemfile, and run `bundle install` (so that any gems you want —
14
+ for example, the gem you’re testing — are available to that Rails installation);
15
+ * Populate that installation by using one or more "template directories" that you provide — each template directory
16
+ is laid out exactly like a standard Rails tree (but need contain only files you actually want to provide), and will
17
+ overwrite the corresponding files in the Rails tree
18
+ * Spin up a new Rails server, running on a randomly-assigned port, in that Rails installation;
19
+ * Fetch arbitrary URLs from that Rails server on your command;
20
+ * When it’s all done, safely (and reliably) terminate that server.
21
+
22
+ As of this writing, this gem is not fully productized: while it works reliably, there is insufficient documentation
23
+ to easily use it yourself. It is, however, very reliable: it is used as the backbone of the test suites for
24
+ [`fortitude`](https://github.com/ageweke/fortitude), [`parcels`](https://github.com/ageweke/parcels), and the
25
+ backbone of the real work in [`rails_view_benchmarks`](https://github.com/ageweke/rails_view_benchmarks).
4
26
 
5
27
  ## Installation
6
28
 
@@ -152,12 +152,6 @@ it should return the fully-qualified path to the root of your project (gem, appl
152
152
  end
153
153
  end
154
154
 
155
- def oop_rails_server_base_templates
156
- [
157
- File.expand_path(File.join(File.dirname(__FILE__), '../../templates/oop_rails_server_base'))
158
- ]
159
- end
160
-
161
155
  def rails_server_implicit_template_paths
162
156
  [ ]
163
157
  end
@@ -185,7 +179,6 @@ it should return the fully-qualified path to the root of your project (gem, appl
185
179
  server = rails_servers[name]
186
180
  server ||= begin
187
181
  templates =
188
- oop_rails_server_base_templates +
189
182
  rails_server_implicit_template_paths +
190
183
  templates
191
184
 
@@ -2,21 +2,24 @@ require 'fileutils'
2
2
  require 'find'
3
3
  require 'net/http'
4
4
  require 'uri'
5
+ require 'file/tail'
5
6
 
6
7
  module OopRailsServer
7
8
  class RailsServer
8
- attr_reader :rails_root, :rails_version, :name
9
+ attr_reader :rails_root, :rails_version, :name, :actual_rails_version, :actual_ruby_version, :actual_ruby_engine
9
10
 
10
11
  def initialize(options)
11
12
  options.assert_valid_keys(
12
13
  :name, :template_paths, :runtime_base_directory,
13
- :rails_version, :rails_env, :additional_gemfile_lines
14
+ :rails_version, :rails_env, :additional_gemfile_lines,
15
+ :log, :verbose
14
16
  )
15
17
 
16
18
  @name = options[:name] || raise(ArgumentError, "You must specify a name for the Rails server")
17
19
 
18
20
  @template_paths = options[:template_paths] || raise(ArgumentError, "You must specify one or more template paths")
19
21
  @template_paths = Array(@template_paths).map { |t| File.expand_path(t) }
22
+ @template_paths = base_template_directories + @template_paths
20
23
 
21
24
  @runtime_base_directory = options[:runtime_base_directory] || raise(ArgumentError, "You must specify a runtime_base_directory")
22
25
  @runtime_base_directory = File.expand_path(@runtime_base_directory)
@@ -24,6 +27,9 @@ module OopRailsServer
24
27
  @rails_version = options[:rails_version] || :default
25
28
  @rails_env = (options[:rails_env] || 'production').to_s
26
29
 
30
+ @log = options[:log] || $stderr
31
+ @verbose = options.fetch(:verbose, true)
32
+
27
33
  @additional_gemfile_lines = Array(options[:additional_gemfile_lines] || [ ])
28
34
 
29
35
 
@@ -36,22 +42,61 @@ module OopRailsServer
36
42
  do_start! unless server_pid
37
43
  end
38
44
 
45
+ def setup!
46
+ @set_up ||= begin
47
+ Bundler.with_clean_env do
48
+ with_rails_env do
49
+ setup_directories!
50
+
51
+ in_rails_root_parent do
52
+ splat_bootstrap_gemfile!
53
+ rails_new!
54
+ update_gemfile!
55
+ end
56
+
57
+ in_rails_root do
58
+ run_bundle_install!(:primary)
59
+ splat_template_files!
60
+ end
61
+ end
62
+ end
63
+
64
+ true
65
+ end
66
+ end
67
+
39
68
  def stop!
40
69
  stop_server! if server_pid
41
70
  end
42
71
 
43
- def get(path, options = { })
44
- out = get_response(path, options)
72
+ def get(path_or_uri, options = { })
73
+ out = get_response(path_or_uri, options)
45
74
  out.body.strip if out
46
75
  end
47
76
 
48
- def uri_for(path)
49
- uri_string = "http://localhost:#{@port}/#{path}"
50
- URI.parse(uri_string)
77
+ def uri_for(path_or_uri, query_values = nil)
78
+ query_values ||= { }
79
+
80
+ if path_or_uri.kind_of?(::URI)
81
+ path_or_uri
82
+ else
83
+ uri_string = "http://#{localhost_name}:#{@port}/#{path_or_uri}"
84
+ if query_values.length > 0
85
+ uri_string += ("?" + query_values.map { |k,v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" }.join("&"))
86
+ end
87
+ URI.parse(uri_string)
88
+ end
89
+ end
90
+
91
+ def localhost_name
92
+ "127.0.0.1"
51
93
  end
52
94
 
53
- def get_response(path, options = { })
54
- uri = uri_for(path)
95
+ def get_response(path_or_uri, options = { })
96
+ options.assert_valid_keys(:ignore_status_code, :nil_on_not_found, :query, :no_layout)
97
+
98
+ uri = uri_for(path_or_uri, options[:query])
99
+ # say "[fetch '#{uri}']"
55
100
  data = Net::HTTP.get_response(uri)
56
101
 
57
102
  if (data.code.to_s != '200')
@@ -79,22 +124,20 @@ module OopRailsServer
79
124
  private
80
125
  attr_reader :template_paths, :runtime_base_directory, :rails_env, :additional_gemfile_lines, :port, :server_pid
81
126
 
127
+ def base_template_directories
128
+ [
129
+ File.expand_path(File.join(File.dirname(__FILE__), '../../templates/oop_rails_server_base'))
130
+ ]
131
+ end
132
+
82
133
  def do_start!
134
+ setup!
135
+
83
136
  Bundler.with_clean_env do
84
137
  with_rails_env do
85
- setup_directories!
86
-
87
- in_rails_root_parent do
88
- splat_bootstrap_gemfile!
89
- rails_new!
90
- update_gemfile!
91
- end
92
-
93
138
  in_rails_root do
94
- run_bundle_install!(:primary)
95
- splat_template_files!
96
139
  start_server!
97
- verify_server!
140
+ verify_server_and_shut_down_if_fails!
98
141
  end
99
142
  end
100
143
  end
@@ -174,6 +217,7 @@ EOS
174
217
  gemfile_contents << "\ngem 'execjs', '~> 2.0.0'\n" if RUBY_VERSION =~ /^1\.8\./
175
218
 
176
219
  gemfile_contents << additional_gemfile_lines.join("\n")
220
+ gemfile_contents << "\n"
177
221
 
178
222
  File.open(gemfile, 'w') { |f| f << gemfile_contents }
179
223
  end
@@ -218,8 +262,12 @@ EOS
218
262
  end
219
263
  end
220
264
 
265
+ def server_output_file
266
+ @server_output_file ||= File.join(rails_root, 'log', 'rails-server.out')
267
+ end
268
+
221
269
  def start_server!
222
- output = File.join(rails_root, 'log', 'rails-server.out')
270
+ output = server_output_file
223
271
  cmd = "rails server -p #{port} > '#{output}' 2>&1"
224
272
  safe_system(cmd, "starting 'rails server' on port #{port}", :background => true)
225
273
 
@@ -238,8 +286,58 @@ EOS
238
286
  end
239
287
  end
240
288
 
289
+ def verify_server_and_shut_down_if_fails!
290
+ begin
291
+ verify_server!
292
+ rescue Exception => e
293
+ begin
294
+ stop_server!
295
+ rescue Exception => e
296
+ say "WARNING: Verification of server failed, so we tried to stop it, but we couldn't do that. Proceeding, but you may have a Rails server left around anyway..."
297
+ end
298
+
299
+ raise
300
+ end
301
+ end
302
+
303
+ class FailedStartupError < StandardError
304
+ attr_reader :timeout, :verify_exception, :server_logfile, :last_lines
305
+
306
+ def initialize(timeout, verify_exception, server_logfile, last_lines)
307
+ message = %{The out-of-process Rails server failed to start up properly and start responding to requests,
308
+ even after #{timeout.round} seconds. This typically means you've added code that prevents it from
309
+ even starting up -- most likely, a syntax error in a class or other error that stops it
310
+ dead in its tracks. (oop_rails_server starts up Rails servers in the production environment
311
+ by default, and, in production, Rails eagerly loads all classes at startup time.)}
312
+
313
+ if server_logfile
314
+ message << %{
315
+
316
+ Any errors will be located in the stdout/stderr of the Rails process, which is at:
317
+ '#{server_logfile}'}
318
+ end
319
+
320
+ if last_lines
321
+ message << %{
322
+
323
+ The last #{last_lines.length} lines of this log are:
324
+
325
+ #{last_lines.join("\n")}}
326
+ end
327
+
328
+ super(message)
329
+
330
+ @timeout = timeout
331
+ @verify_exception = verify_exception
332
+ @server_logfile = server_logfile
333
+ @last_lines = last_lines
334
+ end
335
+ end
336
+
337
+ SERVER_VERIFY_TIMEOUT = 5
338
+
241
339
  def verify_server!
242
- server_verify_url = "http://localhost:#{port}/working/rails_is_working"
340
+ server_verify_url = "http://#{localhost_name}:#{port}/working/rails_is_working"
243
341
  uri = URI.parse(server_verify_url)
244
342
 
245
343
  data = nil
@@ -247,8 +345,24 @@ EOS
247
345
  while (! data)
248
346
  begin
249
347
  data = Net::HTTP.get_response(uri)
250
- rescue Errno::ECONNREFUSED, EOFError
251
- raise if Time.now > (start_time + 20)
348
+ rescue Errno::ECONNREFUSED, EOFError => e
349
+ if Time.now > (start_time + SERVER_VERIFY_TIMEOUT)
350
+ last_lines = server_logfile = nil
351
+ if File.exist?(server_output_file) && File.readable?(server_output_file)
352
+ server_logfile = server_output_file
353
+ File::Tail::Logfile.open(server_output_file, :break_if_eof => true) do |f|
354
+ f.extend(File::Tail)
355
+ last_lines ||= [ ]
356
+ begin
357
+ f.tail(100) { |l| last_lines << l }
358
+ rescue File::Tail::BreakException
359
+ # ok
360
+ end
361
+ end
362
+ end
363
+
364
+ raise FailedStartupError.new(Time.now - start_time, e, server_logfile, last_lines)
365
+ end
252
366
  # keep waiting
253
367
  sleep 0.1
254
368
  end
@@ -259,17 +373,22 @@ EOS
259
373
  end
260
374
  result = data.body.strip
261
375
 
262
- unless result =~ /^Rails\s+version\s*:\s*(\d+\.\d+\.\d+)\n+Ruby\s+version\s*:\s*(\d+\..*?)\s*$/
376
+ unless result =~ /^Rails\s+version\s*:\s*(\d+\.\d+\.\d+)\s*\n+\s*Ruby\s+version\s*:\s*(\d+\..*?)\s*\n+\s*Ruby\s+engine:\s*(.*?)\s*\n?$/mi
263
377
  raise "'#{server_verify_url}' returned: #{result.inspect}"
264
378
  end
265
379
  actual_version = $1
266
380
  ruby_version = $2
381
+ ruby_engine = $3
267
382
 
268
383
  if rails_version != :default && (actual_version != rails_version)
269
384
  raise "We seem to have spawned the wrong version of Rails; wanted: #{rails_version.inspect} but got: #{actual_version.inspect}"
270
385
  end
271
386
 
272
- say "Successfully spawned a server running Rails #{actual_version} (Ruby #{ruby_version}) on port #{port}."
387
+ @actual_rails_version = actual_version
388
+ @actual_ruby_version = ruby_version
389
+ @actual_ruby_engine = ruby_engine
390
+
391
+ say "Successfully spawned a server running Rails #{actual_version} (Ruby #{ruby_version}, engine #{ruby_engine.inspect}) on port #{port}."
273
392
  end
274
393
 
275
394
  def is_alive?(pid)
@@ -379,12 +498,14 @@ and output:
379
498
  end
380
499
 
381
500
  def say(s, newline = true)
382
- if newline
383
- $stdout.puts s
384
- else
385
- $stdout << s
501
+ if @verbose
502
+ if newline
503
+ @log.puts s
504
+ else
505
+ @log << s
506
+ end
507
+ @log.flush
386
508
  end
387
- $stdout.flush
388
509
  end
389
510
 
390
511
  def safe_system(cmd, notice = nil, options = { })
@@ -1,3 +1,3 @@
1
1
  module OopRailsServer
2
- VERSION = "0.0.7"
2
+ VERSION = "0.0.8"
3
3
  end
@@ -18,6 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.require_paths = ["lib"]
19
19
 
20
20
  spec.add_dependency 'json'
21
+ spec.add_dependency 'file-tail'
21
22
 
22
23
  spec.add_development_dependency "bundler", "~> 1.6"
23
24
  spec.add_development_dependency "rake", "~> 10.0"
@@ -1,5 +1,5 @@
1
1
  class WorkingController < ApplicationController
2
2
  def rails_is_working
3
- render :text => "Rails version: #{Rails.version}\nRuby version: #{RUBY_VERSION}"
3
+ render :text => "Rails version: #{Rails.version}\nRuby version: #{RUBY_VERSION}\nRuby engine: #{RUBY_ENGINE}\n"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,58 +1,79 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: oop_rails_server
3
- version: !ruby/object:Gem::Version
4
- version: 0.0.7
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.8
5
5
  platform: ruby
6
- authors:
6
+ authors:
7
7
  - Andrew Geweke
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
-
12
- date: 2015-01-22 00:00:00 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
11
+ date: 2015-04-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
15
14
  name: json
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
16
21
  prerelease: false
17
- requirement: &id001 !ruby/object:Gem::Requirement
18
- requirements:
19
- - &id004
20
- - ">="
21
- - !ruby/object:Gem::Version
22
- version: "0"
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: file-tail
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
23
34
  type: :runtime
24
- version_requirements: *id001
25
- - !ruby/object:Gem::Dependency
26
- name: bundler
27
35
  prerelease: false
28
- requirement: &id002 !ruby/object:Gem::Requirement
29
- requirements:
30
- - - ~>
31
- - !ruby/object:Gem::Version
32
- version: "1.6"
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.6'
33
48
  type: :development
34
- version_requirements: *id002
35
- - !ruby/object:Gem::Dependency
36
- name: rake
37
49
  prerelease: false
38
- requirement: &id003 !ruby/object:Gem::Requirement
39
- requirements:
40
- - - ~>
41
- - !ruby/object:Gem::Version
42
- version: "10.0"
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
43
62
  type: :development
44
- version_requirements: *id003
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
45
69
  description:
46
- email:
70
+ email:
47
71
  - andrew@geweke.org
48
72
  executables: []
49
-
50
73
  extensions: []
51
-
52
74
  extra_rdoc_files: []
53
-
54
- files:
55
- - .gitignore
75
+ files:
76
+ - ".gitignore"
56
77
  - CHANGES.md
57
78
  - Gemfile
58
79
  - LICENSE.txt
@@ -69,27 +90,28 @@ files:
69
90
  - templates/oop_rails_server_base/config/routes.rb
70
91
  - templates/oop_rails_server_base/config/secrets.yml
71
92
  homepage: https://github.com/ageweke/oop_rails_server
72
- licenses:
93
+ licenses:
73
94
  - MIT
74
95
  metadata: {}
75
-
76
96
  post_install_message:
77
97
  rdoc_options: []
78
-
79
- require_paths:
98
+ require_paths:
80
99
  - lib
81
- required_ruby_version: !ruby/object:Gem::Requirement
82
- requirements:
83
- - *id004
84
- required_rubygems_version: !ruby/object:Gem::Requirement
85
- requirements:
86
- - *id004
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
87
110
  requirements: []
88
-
89
111
  rubyforge_project:
90
112
  rubygems_version: 2.4.5
91
113
  signing_key:
92
114
  specification_version: 4
93
- summary: Reliably runs a Rails server in a separate process, for use in tests, utilities, etc.
115
+ summary: Reliably runs a Rails server in a separate process, for use in tests, utilities,
116
+ etc.
94
117
  test_files: []
95
-