oop_rails_server 0.0.7 → 0.0.8

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