aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actioncable/lib/action_cable/connection/stream.rb1
-rw-r--r--actioncable/test/connection/client_socket_test.rb14
-rw-r--r--actionpack/lib/action_dispatch.rb1
-rw-r--r--actionpack/lib/action_dispatch/middleware/debug_exceptions.rb8
-rw-r--r--actionpack/lib/action_dispatch/middleware/debug_locks.rb122
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb7
-rw-r--r--actionpack/test/dispatch/debug_exceptions_test.rb23
-rw-r--r--activerecord/lib/active_record/relation.rb2
-rw-r--r--activerecord/test/cases/primary_keys_test.rb8
-rw-r--r--activesupport/lib/active_support/concurrency/latch.rb17
-rw-r--r--activesupport/lib/active_support/concurrency/share_lock.rb50
-rw-r--r--activesupport/lib/active_support/dependencies/interlock.rb4
-rw-r--r--activesupport/lib/active_support/inflector/methods.rb8
-rw-r--r--activesupport/test/testing/file_fixtures_test.rb4
-rw-r--r--railties/CHANGELOG.md8
-rw-r--r--railties/lib/rails/generators/app_base.rb2
-rw-r--r--railties/lib/rails/generators/rails/plugin/plugin_generator.rb2
-rw-r--r--railties/test/generators/app_generator_test.rb87
-rw-r--r--railties/test/generators/plugin_generator_test.rb81
-rw-r--r--railties/test/generators/shared_generator_tests.rb35
20 files changed, 362 insertions, 122 deletions
diff --git a/actioncable/lib/action_cable/connection/stream.rb b/actioncable/lib/action_cable/connection/stream.rb
index 0cf59091bc..c250cf92fc 100644
--- a/actioncable/lib/action_cable/connection/stream.rb
+++ b/actioncable/lib/action_cable/connection/stream.rb
@@ -50,6 +50,7 @@ module ActionCable
def clean_rack_hijack
return unless @rack_hijack_io
@event_loop.detach(@rack_hijack_io, self)
+ @rack_hijack_io.close
@rack_hijack_io = nil
end
end
diff --git a/actioncable/test/connection/client_socket_test.rb b/actioncable/test/connection/client_socket_test.rb
index 4af071b4da..fe9077ae7f 100644
--- a/actioncable/test/connection/client_socket_test.rb
+++ b/actioncable/test/connection/client_socket_test.rb
@@ -48,6 +48,20 @@ class ActionCable::Connection::ClientSocketTest < ActionCable::TestCase
end
end
+ test 'closes hijacked i/o socket at shutdown' do
+ skip if ENV['FAYE'].present?
+
+ run_in_eventmachine do
+ connection = open_connection
+
+ client = connection.websocket.send(:websocket)
+ client.instance_variable_get('@stream')
+ .instance_variable_get('@rack_hijack_io')
+ .expects(:close)
+ connection.close
+ end
+ end
+
private
def open_connection
env = Rack::MockRequest.env_for '/test',
diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb
index 01d49475de..17aa115f15 100644
--- a/actionpack/lib/action_dispatch.rb
+++ b/actionpack/lib/action_dispatch.rb
@@ -50,6 +50,7 @@ module ActionDispatch
autoload :Callbacks
autoload :Cookies
autoload :DebugExceptions
+ autoload :DebugLocks
autoload :ExceptionWrapper
autoload :Executor
autoload :Flash
diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
index 5f758d641a..8974258cf7 100644
--- a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
@@ -36,6 +36,14 @@ module ActionDispatch
def debug_hash(object)
object.to_hash.sort_by { |k, _| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n")
end
+
+ def render(*)
+ if logger = ActionView::Base.logger
+ logger.silence { super }
+ else
+ super
+ end
+ end
end
def initialize(app, routes_app = nil, response_format = :default)
diff --git a/actionpack/lib/action_dispatch/middleware/debug_locks.rb b/actionpack/lib/action_dispatch/middleware/debug_locks.rb
new file mode 100644
index 0000000000..13254d08de
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/debug_locks.rb
@@ -0,0 +1,122 @@
+module ActionDispatch
+ # This middleware can be used to diagnose deadlocks in the autoload interlock.
+ #
+ # To use it, insert it near the top of the middleware stack, using
+ # <tt>config/application.rb</tt>:
+ #
+ # config.middleware.insert_before Rack::Sendfile, ActionDispatch::DebugLocks
+ #
+ # After restarting the application and re-triggering the deadlock condition,
+ # <tt>/rails/locks</tt> will show a summary of all threads currently known to
+ # the interlock, which lock level they are holding or awaiting, and their
+ # current backtrace.
+ #
+ # Generally a deadlock will be caused by the interlock conflicting with some
+ # other external lock or blocking I/O call. These cannot be automatically
+ # identified, but should be visible in the displayed backtraces.
+ #
+ # NOTE: The formatting and content of this middleware's output is intended for
+ # human consumption, and should be expected to change between releases.
+ #
+ # This middleware exposes operational details of the server, with no access
+ # control. It should only be enabled when in use, and removed thereafter.
+ class DebugLocks
+ def initialize(app, path = '/rails/locks')
+ @app = app
+ @path = path
+ end
+
+ def call(env)
+ req = ActionDispatch::Request.new env
+
+ if req.get?
+ path = req.path_info.chomp('/'.freeze)
+ if path == @path
+ return render_details(req)
+ end
+ end
+
+ @app.call(env)
+ end
+
+ private
+ def render_details(req)
+ threads = ActiveSupport::Dependencies.interlock.raw_state do |threads|
+ # The Interlock itself comes to a complete halt as long as this block
+ # is executing. That gives us a more consistent picture of everything,
+ # but creates a pretty strong Observer Effect.
+ #
+ # Most directly, that means we need to do as little as possible in
+ # this block. More widely, it means this middleware should remain a
+ # strictly diagnostic tool (to be used when something has gone wrong),
+ # and not for any sort of general monitoring.
+
+ threads.each.with_index do |(thread, info), idx|
+ info[:index] = idx
+ info[:backtrace] = thread.backtrace
+ end
+
+ threads
+ end
+
+ str = threads.map do |thread, info|
+ if info[:exclusive]
+ lock_state = 'Exclusive'
+ elsif info[:sharing] > 0
+ lock_state = 'Sharing'
+ lock_state << " x#{info[:sharing]}" if info[:sharing] > 1
+ else
+ lock_state = 'No lock'
+ end
+
+ if info[:waiting]
+ lock_state << ' (yielded share)'
+ end
+
+ msg = "Thread #{info[:index]} [0x#{thread.__id__.to_s(16)} #{thread.status || 'dead'}] #{lock_state}\n"
+
+ if info[:sleeper]
+ msg << " Waiting in #{info[:sleeper]}"
+ msg << " to #{info[:purpose].to_s.inspect}" unless info[:purpose].nil?
+ msg << "\n"
+
+ if info[:compatible]
+ compat = info[:compatible].map { |c| c == false ? "share" : c.to_s.inspect }
+ msg << " may be pre-empted for: #{compat.join(', ')}\n"
+ end
+
+ blockers = threads.values.select { |binfo| blocked_by?(info, binfo, threads.values) }
+ msg << " blocked by: #{blockers.map {|i| i[:index] }.join(', ')}\n" if blockers.any?
+ end
+
+ blockees = threads.values.select { |binfo| blocked_by?(binfo, info, threads.values) }
+ msg << " blocking: #{blockees.map {|i| i[:index] }.join(', ')}\n" if blockees.any?
+
+ msg << "\n#{info[:backtrace].join("\n")}\n" if info[:backtrace]
+ end.join("\n\n---\n\n\n")
+
+ [200, { "Content-Type" => "text/plain", "Content-Length" => str.size }, [str]]
+ end
+
+ def blocked_by?(victim, blocker, all_threads)
+ return false if victim.equal?(blocker)
+
+ case victim[:sleeper]
+ when :start_sharing
+ blocker[:exclusive] ||
+ (!victim[:waiting] && blocker[:compatible] && !blocker[:compatible].include?(false))
+ when :start_exclusive
+ blocker[:sharing] > 0 ||
+ blocker[:exclusive] ||
+ (blocker[:compatible] && !blocker[:compatible].include?(victim[:purpose]))
+ when :yield_shares
+ blocker[:exclusive]
+ when :stop_exclusive
+ blocker[:exclusive] ||
+ victim[:compatible] &&
+ victim[:compatible].include?(blocker[:purpose]) &&
+ all_threads.all? { |other| !other[:compatible] || blocker.equal?(other) || other[:compatible].include?(blocker[:purpose]) }
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index 5627e79bb7..10cd1e5787 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -423,8 +423,11 @@ module ActionDispatch
end
def append_format_to(path)
- path << @path_format unless @url_encoded_form
- path
+ if @url_encoded_form
+ path
+ else
+ path + @path_format
+ end
end
def content_type
diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb
index 5a39db145e..6f3d30ebf9 100644
--- a/actionpack/test/dispatch/debug_exceptions_test.rb
+++ b/actionpack/test/dispatch/debug_exceptions_test.rb
@@ -362,6 +362,29 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
assert_match(/puke/, output.rewind && output.read)
end
+ test 'logs only what is necessary' do
+ @app = DevelopmentApp
+ io = StringIO.new
+ logger = ActiveSupport::Logger.new(io)
+
+ _old, ActionView::Base.logger = ActionView::Base.logger, logger
+ begin
+ get "/", headers: { 'action_dispatch.show_exceptions' => true, 'action_dispatch.logger' => logger }
+ ensure
+ ActionView::Base.logger = _old
+ end
+
+ output = io.rewind && io.read
+ lines = output.lines
+
+ # Other than the first three...
+ assert_equal([" \n", "RuntimeError (puke!):\n", " \n"], lines.slice!(0, 3))
+ lines.each do |line|
+ # .. all the remaining lines should be from the backtrace
+ assert_match(/:\d+:in /, line)
+ end
+ end
+
test 'uses backtrace cleaner from env' do
@app = DevelopmentApp
backtrace_cleaner = ActiveSupport::BacktraceCleaner.new
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 7a1552856b..93baa882ad 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -65,7 +65,7 @@ module ActiveRecord
@klass.connection.insert(
im,
'SQL',
- primary_key,
+ primary_key || false,
primary_key_value,
nil,
binds)
diff --git a/activerecord/test/cases/primary_keys_test.rb b/activerecord/test/cases/primary_keys_test.rb
index 6c8532cf00..4267ad4a24 100644
--- a/activerecord/test/cases/primary_keys_test.rb
+++ b/activerecord/test/cases/primary_keys_test.rb
@@ -174,6 +174,14 @@ class PrimaryKeysTest < ActiveRecord::TestCase
assert_equal '2', dashboard.id
end
+ def test_create_without_primary_key_no_extra_query
+ klass = Class.new(ActiveRecord::Base) do
+ self.table_name = 'dashboards'
+ end
+ klass.create! # warmup schema cache
+ assert_queries(3, ignore_none: true) { klass.create! }
+ end
+
if current_adapter?(:PostgreSQLAdapter)
def test_serial_with_quoted_sequence_name
column = MixedCaseMonkey.columns_hash[MixedCaseMonkey.primary_key]
diff --git a/activesupport/lib/active_support/concurrency/latch.rb b/activesupport/lib/active_support/concurrency/latch.rb
index 4abe5ece6f..35074265b8 100644
--- a/activesupport/lib/active_support/concurrency/latch.rb
+++ b/activesupport/lib/active_support/concurrency/latch.rb
@@ -2,17 +2,24 @@ require 'concurrent/atomic/count_down_latch'
module ActiveSupport
module Concurrency
- class Latch < Concurrent::CountDownLatch
+ class Latch
def initialize(count = 1)
- ActiveSupport::Deprecation.warn("ActiveSupport::Concurrency::Latch is deprecated. Please use Concurrent::CountDownLatch instead.")
- super(count)
+ if count == 1
+ ActiveSupport::Deprecation.warn("ActiveSupport::Concurrency::Latch is deprecated. Please use Concurrent::Event instead.")
+ else
+ ActiveSupport::Deprecation.warn("ActiveSupport::Concurrency::Latch is deprecated. Please use Concurrent::CountDownLatch instead.")
+ end
+
+ @inner = Concurrent::CountDownLatch.new(count)
end
- alias_method :release, :count_down
+ def release
+ @inner.count_down
+ end
def await
- wait(nil)
+ @inner.wait(nil)
end
end
end
diff --git a/activesupport/lib/active_support/concurrency/share_lock.rb b/activesupport/lib/active_support/concurrency/share_lock.rb
index 89e63aefd4..cf632ea7b0 100644
--- a/activesupport/lib/active_support/concurrency/share_lock.rb
+++ b/activesupport/lib/active_support/concurrency/share_lock.rb
@@ -14,6 +14,38 @@ module ActiveSupport
# to upgrade share locks to exclusive.
+ def raw_state # :nodoc:
+ synchronize do
+ threads = @sleeping.keys | @sharing.keys | @waiting.keys
+ threads |= [@exclusive_thread] if @exclusive_thread
+
+ data = {}
+
+ threads.each do |thread|
+ purpose, compatible = @waiting[thread]
+
+ data[thread] = {
+ thread: thread,
+ sharing: @sharing[thread],
+ exclusive: @exclusive_thread == thread,
+ purpose: purpose,
+ compatible: compatible,
+ waiting: !!@waiting[thread],
+ sleeper: @sleeping[thread],
+ }
+ end
+
+ # NB: Yields while holding our *internal* synchronize lock,
+ # which is supposed to be used only for a few instructions at
+ # a time. This allows the caller to inspect additional state
+ # without things changing out from underneath, but would have
+ # disastrous effects upon normal operation. Fortunately, this
+ # method is only intended to be called when things have
+ # already gone wrong.
+ yield data
+ end
+ end
+
def initialize
super()
@@ -21,6 +53,7 @@ module ActiveSupport
@sharing = Hash.new(0)
@waiting = {}
+ @sleeping = {}
@exclusive_thread = nil
@exclusive_depth = 0
end
@@ -46,7 +79,7 @@ module ActiveSupport
return false if no_wait
yield_shares(purpose: purpose, compatible: compatible, block_share: true) do
- @cv.wait_while { busy_for_exclusive?(purpose) }
+ wait_for(:start_exclusive) { busy_for_exclusive?(purpose) }
end
end
@exclusive_thread = Thread.current
@@ -69,7 +102,7 @@ module ActiveSupport
if eligible_waiters?(compatible)
yield_shares(compatible: compatible, block_share: true) do
- @cv.wait_while { @exclusive_thread || eligible_waiters?(compatible) }
+ wait_for(:stop_exclusive) { @exclusive_thread || eligible_waiters?(compatible) }
end
end
@cv.broadcast
@@ -84,11 +117,11 @@ module ActiveSupport
elsif @waiting[Thread.current]
# We're nested inside a +yield_shares+ call: we'll resume as
# soon as there isn't an exclusive lock in our way
- @cv.wait_while { @exclusive_thread }
+ wait_for(:start_sharing) { @exclusive_thread }
else
# This is an initial / outermost share call: any outstanding
# requests for an exclusive lock get to go first
- @cv.wait_while { busy_for_sharing?(false) }
+ wait_for(:start_sharing) { busy_for_sharing?(false) }
end
@sharing[Thread.current] += 1
end
@@ -153,7 +186,7 @@ module ActiveSupport
yield
ensure
synchronize do
- @cv.wait_while { @exclusive_thread && @exclusive_thread != Thread.current }
+ wait_for(:yield_shares) { @exclusive_thread && @exclusive_thread != Thread.current }
if previous_wait
@waiting[Thread.current] = previous_wait
@@ -181,6 +214,13 @@ module ActiveSupport
def eligible_waiters?(compatible)
@waiting.any? { |t, (p, _)| compatible.include?(p) && @waiting.all? { |t2, (_, c2)| t == t2 || c2.include?(p) } }
end
+
+ def wait_for(method)
+ @sleeping[Thread.current] = method
+ @cv.wait_while { yield }
+ ensure
+ @sleeping.delete Thread.current
+ end
end
end
end
diff --git a/activesupport/lib/active_support/dependencies/interlock.rb b/activesupport/lib/active_support/dependencies/interlock.rb
index f1865ca2f8..75b769574c 100644
--- a/activesupport/lib/active_support/dependencies/interlock.rb
+++ b/activesupport/lib/active_support/dependencies/interlock.rb
@@ -46,6 +46,10 @@ module ActiveSupport #:nodoc:
yield
end
end
+
+ def raw_state(&block) # :nodoc:
+ @lock.raw_state(&block)
+ end
end
end
end
diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb
index f94e12e14f..f14b8b81b7 100644
--- a/activesupport/lib/active_support/inflector/methods.rb
+++ b/activesupport/lib/active_support/inflector/methods.rb
@@ -238,8 +238,8 @@ module ActiveSupport
# Tries to find a constant with the name specified in the argument string.
#
- # 'Module'.constantize # => Module
- # 'Foo::Bar'.constantize # => Foo::Bar
+ # constantize('Module') # => Module
+ # constantize('Foo::Bar') # => Foo::Bar
#
# The name is assumed to be the one of a top-level constant, no matter
# whether it starts with "::" or not. No lexical context is taken into
@@ -248,8 +248,8 @@ module ActiveSupport
# C = 'outside'
# module M
# C = 'inside'
- # C # => 'inside'
- # 'C'.constantize # => 'outside', same as ::C
+ # C # => 'inside'
+ # constantize('C') # => 'outside', same as ::C
# end
#
# NameError is raised when the name is not in CamelCase or the constant is
diff --git a/activesupport/test/testing/file_fixtures_test.rb b/activesupport/test/testing/file_fixtures_test.rb
index 91b8a9071c..3587c1a4d1 100644
--- a/activesupport/test/testing/file_fixtures_test.rb
+++ b/activesupport/test/testing/file_fixtures_test.rb
@@ -6,7 +6,7 @@ class FileFixturesTest < ActiveSupport::TestCase
test "#file_fixture returns Pathname to file fixture" do
path = file_fixture("sample.txt")
assert_kind_of Pathname, path
- assert_match %r{activesupport/test/file_fixtures/sample.txt$}, path.to_s
+ assert_match %r{.*/test/file_fixtures/sample.txt$}, path.to_s
end
test "raises an exception when the fixture file does not exist" do
@@ -23,6 +23,6 @@ class FileFixturesPathnameDirectoryTest < ActiveSupport::TestCase
test "#file_fixture_path returns Pathname to file fixture" do
path = file_fixture("sample.txt")
assert_kind_of Pathname, path
- assert_match %r{activesupport/test/file_fixtures/sample.txt$}, path.to_s
+ assert_match %r{.*/test/file_fixtures/sample.txt$}, path.to_s
end
end
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 83fe6f56a4..243f40a057 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,3 +1,11 @@
+* Do not run `bundle install` when generating a new plugin.
+
+ Since bundler 1.12.0, the gemspec is validated so the `bundle install`
+ command will fail just after the gem is created causing confusion to the
+ users. This change was a bug fix to correctly validate gemspecs.
+
+ *Rafael Mendonça França*
+
* Default `config.assets.quiet = true` in the development environment. Suppress
logging of `sprockets-rails` requests by default.
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index 0835c09323..af3c6dead3 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -242,7 +242,7 @@ module Rails
] + dev_edge_common
elsif options.edge?
[
- GemfileEntry.github('rails', 'rails/rails')
+ GemfileEntry.github('rails', 'rails/rails', '5-0-stable')
] + dev_edge_common
else
[GemfileEntry.version('rails',
diff --git a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
index 56efd35a95..7f427947f5 100644
--- a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
+++ b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
@@ -258,7 +258,7 @@ task default: :test
build(:leftovers)
end
- public_task :apply_rails_template, :run_bundle
+ public_task :apply_rails_template
def run_after_bundle_callbacks
@after_bundle_callbacks.each do |callback|
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index 058308aa13..ac1488abb3 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -597,6 +597,21 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
end
+ def test_generation_runs_bundle_install
+ assert_generates_with_bundler
+ end
+
+ def test_dev_option
+ assert_generates_with_bundler dev: true
+ rails_path = File.expand_path('../../..', Rails.root)
+ assert_file 'Gemfile', /^gem\s+["']rails["'],\s+path:\s+["']#{Regexp.escape(rails_path)}["']$/
+ end
+
+ def test_edge_option
+ assert_generates_with_bundler edge: true
+ assert_file 'Gemfile', %r{^gem\s+["']rails["'],\s+github:\s+["']#{Regexp.escape("rails/rails")}["'],\s+branch:\s+["']#{Regexp.escape("5-0-stable")}["']$}
+ end
+
def test_spring
run_generator
assert_gem 'spring'
@@ -754,41 +769,61 @@ class AppGeneratorTest < Rails::Generators::TestCase
protected
- def stub_rails_application(root)
- Rails.application.config.root = root
- Rails.application.class.stub(:name, "Myapp") do
- yield
+ def stub_rails_application(root)
+ Rails.application.config.root = root
+ Rails.application.class.stub(:name, "Myapp") do
+ yield
+ end
end
- end
- def action(*args, &block)
- capture(:stdout) { generator.send(*args, &block) }
- end
+ def action(*args, &block)
+ capture(:stdout) { generator.send(*args, &block) }
+ end
- def assert_gem(gem, constraint = nil)
- if constraint
- assert_file "Gemfile", /^\s*gem\s+["']#{gem}["'], #{constraint}$*/
- else
- assert_file "Gemfile", /^\s*gem\s+["']#{gem}["']$*/
+ def assert_gem(gem, constraint = nil)
+ if constraint
+ assert_file "Gemfile", /^\s*gem\s+["']#{gem}["'], #{constraint}$*/
+ else
+ assert_file "Gemfile", /^\s*gem\s+["']#{gem}["']$*/
+ end
end
- end
- def assert_listen_related_configuration
- assert_gem 'listen'
- assert_gem 'spring-watcher-listen'
+ def assert_listen_related_configuration
+ assert_gem 'listen'
+ assert_gem 'spring-watcher-listen'
- assert_file 'config/environments/development.rb' do |content|
- assert_match(/^\s*config.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content)
+ assert_file 'config/environments/development.rb' do |content|
+ assert_match(/^\s*config.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content)
+ end
end
- end
- def assert_no_listen_related_configuration
- assert_file 'Gemfile' do |content|
- assert_no_match(/listen/, content)
+ def assert_no_listen_related_configuration
+ assert_file 'Gemfile' do |content|
+ assert_no_match(/listen/, content)
+ end
+
+ assert_file 'config/environments/development.rb' do |content|
+ assert_match(/^\s*# config.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content)
+ end
end
- assert_file 'config/environments/development.rb' do |content|
- assert_match(/^\s*# config.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content)
+ def assert_generates_with_bundler(options = {})
+ generator([destination_root], options)
+
+ command_check = -> command do
+ @install_called ||= 0
+
+ case command
+ when 'install'
+ @install_called += 1
+ assert_equal 1, @install_called, "install expected to be called once, but was called #{@install_called} times"
+ when 'exec spring binstub --all'
+ # Called when running tests with spring, let through unscathed.
+ end
+ end
+
+ generator.stub :bundle_command, command_check do
+ quietly { generator.invoke_all }
+ end
end
- end
end
diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb
index 5dd4cce28a..823dcc50ee 100644
--- a/railties/test/generators/plugin_generator_test.rb
+++ b/railties/test/generators/plugin_generator_test.rb
@@ -193,13 +193,24 @@ class PluginGeneratorTest < Rails::Generators::TestCase
assert_file "test/dummy/config/database.yml", /postgres/
end
- def test_generation_runs_bundle_install_with_full_and_mountable
- result = run_generator [destination_root, "--mountable", "--full", "--dev"]
- assert_match(/run bundle install/, result)
- assert $?.success?, "Command failed: #{result}"
- assert_file "#{destination_root}/Gemfile.lock" do |contents|
- assert_match(/bukkits/, contents)
- end
+ def test_generation_runs_bundle_install
+ assert_generates_without_bundler
+ end
+
+ def test_dev_option
+ assert_generates_without_bundler(dev: true)
+ rails_path = File.expand_path('../../..', Rails.root)
+ assert_file 'Gemfile', /^gem\s+["']rails["'],\s+path:\s+["']#{Regexp.escape(rails_path)}["']$/
+ end
+
+ def test_edge_option
+ assert_generates_without_bundler(edge: true)
+ assert_file 'Gemfile', %r{^gem\s+["']rails["'],\s+github:\s+["']#{Regexp.escape("rails/rails")}["'],\s+branch:\s+["']#{Regexp.escape("5-0-stable")}["']$}
+ end
+
+ def test_generation_does_not_run_bundle_install_with_full_and_mountable
+ assert_generates_without_bundler(mountable: true, full: true, dev: true)
+ assert_no_file "#{destination_root}/Gemfile.lock"
end
def test_skipping_javascripts_without_mountable_option
@@ -697,48 +708,38 @@ class PluginGeneratorTest < Rails::Generators::TestCase
end
end
- def test_after_bundle_callback
- path = 'http://example.org/rails_template'
- template = %{ after_bundle { run 'echo ran after_bundle' } }
- template.instance_eval "def read; self; end" # Make the string respond to read
+ protected
- check_open = -> *args do
- assert_equal [ path, 'Accept' => 'application/x-thor-template' ], args
- template
+ def action(*args, &block)
+ silence(:stdout){ generator.send(*args, &block) }
end
- sequence = ['install', 'echo ran after_bundle']
- @sequence_step ||= 0
- ensure_bundler_first = -> command do
- assert_equal sequence[@sequence_step], command, "commands should be called in sequence #{sequence}"
- @sequence_step += 1
+ def default_files
+ ::DEFAULT_PLUGIN_FILES
end
- generator([destination_root], template: path).stub(:open, check_open, template) do
- generator.stub(:bundle_command, ensure_bundler_first) do
- generator.stub(:run, ensure_bundler_first) do
- quietly { generator.invoke_all }
- end
+ def assert_match_sqlite3(contents)
+ if defined?(JRUBY_VERSION)
+ assert_match(/group :development do\n gem 'activerecord-jdbcsqlite3-adapter'\nend/, contents)
+ else
+ assert_match(/group :development do\n gem 'sqlite3'\nend/, contents)
end
end
- assert_equal 2, @sequence_step
- end
+ def assert_generates_without_bundler(options = {})
+ generator([destination_root], options)
-protected
- def action(*args, &block)
- silence(:stdout){ generator.send(*args, &block) }
- end
-
- def default_files
- ::DEFAULT_PLUGIN_FILES
- end
+ command_check = -> command do
+ case command
+ when 'install'
+ flunk "install expected to not be called"
+ when 'exec spring binstub --all'
+ # Called when running tests with spring, let through unscathed.
+ end
+ end
- def assert_match_sqlite3(contents)
- if defined?(JRUBY_VERSION)
- assert_match(/group :development do\n gem 'activerecord-jdbcsqlite3-adapter'\nend/, contents)
- else
- assert_match(/group :development do\n gem 'sqlite3'\nend/, contents)
+ generator.stub :bundle_command, command_check do
+ quietly { generator.invoke_all }
+ end
end
- end
end
diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb
index e83d54890a..03ea521355 100644
--- a/railties/test/generators/shared_generator_tests.rb
+++ b/railties/test/generators/shared_generator_tests.rb
@@ -26,30 +26,6 @@ module SharedGeneratorTests
default_files.each { |path| assert_file path }
end
- def assert_generates_with_bundler(options = {})
- generator([destination_root], options)
-
- command_check = -> command do
- @install_called ||= 0
-
- case command
- when 'install'
- @install_called += 1
- assert_equal 1, @install_called, "install expected to be called once, but was called #{@install_called} times"
- when 'exec spring binstub --all'
- # Called when running tests with spring, let through unscathed.
- end
- end
-
- generator.stub :bundle_command, command_check do
- quietly { generator.invoke_all }
- end
- end
-
- def test_generation_runs_bundle_install
- assert_generates_with_bundler
- end
-
def test_plugin_new_generate_pretend
run_generator ["testapp", "--pretend"]
default_files.each{ |path| assert_no_file File.join("testapp",path) }
@@ -114,17 +90,6 @@ module SharedGeneratorTests
end
end
- def test_dev_option
- assert_generates_with_bundler dev: true
- rails_path = File.expand_path('../../..', Rails.root)
- assert_file 'Gemfile', /^gem\s+["']rails["'],\s+path:\s+["']#{Regexp.escape(rails_path)}["']$/
- end
-
- def test_edge_option
- assert_generates_with_bundler edge: true
- assert_file 'Gemfile', %r{^gem\s+["']rails["'],\s+github:\s+["']#{Regexp.escape("rails/rails")}["']$}
- end
-
def test_skip_gemfile
assert_not_called(generator([destination_root], skip_gemfile: true), :bundle_command) do
quietly { generator.invoke_all }