aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionmailer/test/abstract_unit.rb4
-rw-r--r--actionmailer/test/base_test.rb4
-rw-r--r--actionpack/CHANGELOG.md18
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb1
-rw-r--r--actionpack/lib/action_dispatch/http/cache.rb8
-rw-r--r--actionpack/lib/action_view/lookup_context.rb2
-rw-r--r--actionpack/test/dispatch/request_test.rb39
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb159
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/transaction.rb156
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb43
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql_adapter.rb3
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb5
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb8
-rw-r--r--activerecord/lib/active_record/core.rb1
-rw-r--r--activerecord/lib/active_record/fixtures.rb9
-rw-r--r--activerecord/lib/active_record/railties/console_sandbox.rb2
-rw-r--r--activerecord/lib/active_record/transactions.rb35
-rw-r--r--activerecord/test/active_record/connection_adapters/fake_adapter.rb4
-rw-r--r--activerecord/test/cases/adapter_test.rb32
-rw-r--r--activerecord/test/cases/transactions_test.rb37
-rw-r--r--activesupport/lib/active_support/core_ext/object/to_json.rb8
-rw-r--r--activesupport/lib/active_support/deprecation/reporting.rb4
-rw-r--r--activesupport/lib/active_support/queueing.rb116
-rw-r--r--activesupport/test/queueing/container_test.rb28
-rw-r--r--activesupport/test/queueing/test_queue_test.rb (renamed from railties/test/queueing/test_queue_test.rb)4
-rw-r--r--activesupport/test/queueing/threaded_consumer_test.rb (renamed from railties/test/queueing/threaded_consumer_test.rb)18
-rw-r--r--guides/source/configuring.textile4
-rw-r--r--railties/lib/rails.rb1
-rw-r--r--railties/lib/rails/application.rb3
-rw-r--r--railties/lib/rails/application/configuration.rb5
-rw-r--r--railties/lib/rails/application/finisher.rb4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt2
-rw-r--r--railties/lib/rails/queueing.rb115
-rw-r--r--railties/test/application/initializers/frameworks_test.rb6
-rw-r--r--railties/test/application/queue_test.rb16
-rw-r--r--railties/test/application/rake/dbs_test.rb12
-rw-r--r--railties/test/queueing/container_test.rb30
40 files changed, 558 insertions, 398 deletions
diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb
index 1167387def..0b418c4ea1 100644
--- a/actionmailer/test/abstract_unit.rb
+++ b/actionmailer/test/abstract_unit.rb
@@ -11,7 +11,7 @@ end
require 'minitest/autorun'
require 'action_mailer'
require 'action_mailer/test_case'
-require 'rails/queueing'
+require 'active_support/queueing'
silence_warnings do
# These external dependencies have warnings :/
@@ -27,7 +27,7 @@ ActionView::Template.register_template_handler :bak, lambda { |template| "Lame b
FIXTURE_LOAD_PATH = File.expand_path('fixtures', File.dirname(__FILE__))
ActionMailer::Base.view_paths = FIXTURE_LOAD_PATH
-ActionMailer::Base.queue = Rails::Queueing::SynchronousQueue.new
+ActionMailer::Base.queue = ActiveSupport::SynchronousQueue.new
class MockSMTP
def self.deliveries
diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb
index 862b954f9e..6a06cec041 100644
--- a/actionmailer/test/base_test.rb
+++ b/actionmailer/test/base_test.rb
@@ -3,13 +3,13 @@ require 'abstract_unit'
require 'set'
require 'action_dispatch'
+require 'active_support/queueing'
require 'active_support/time'
require 'mailers/base_mailer'
require 'mailers/proc_mailer'
require 'mailers/asset_mailer'
require 'mailers/async_mailer'
-require 'rails/queueing'
class BaseTest < ActiveSupport::TestCase
def teardown
@@ -433,7 +433,7 @@ class BaseTest < ActiveSupport::TestCase
end
test "delivering message asynchronously" do
- testing_queue = Rails::Queueing::TestQueue.new
+ testing_queue = ActiveSupport::TestQueue.new
AsyncMailer.delivery_method = :test
AsyncMailer.deliveries.clear
stub_queue(AsyncMailer, testing_queue).welcome.deliver
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 36e8479441..239e4445d3 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,5 +1,23 @@
## Rails 4.0.0 (unreleased) ##
+* Support multiple etags in If-None-Match header. *Travis Warlick*
+
+* Allow to configure how unverified request will be handled using `:with`
+ option in `protect_from_forgery` method.
+
+ Valid unverified request handling methods are:
+
+ - `:exception` - Raises ActionController::InvalidAuthenticityToken exception.
+ - `:reset_session` - Resets the session.
+ - `:null_session` - Provides an empty session during request but doesn't
+ reset it completely. Used as default if `:with` option is not specified.
+
+ New applications are generated with:
+
+ protect_from_forgery :with => :exception
+
+ *Sergey Nartimov*
+
* Add .rb template handler, this handler simply allows arbitrary Ruby code as a template. *Guillermo Iguaran*
* Add `separator` option for `ActionView::Helpers::TextHelper#excerpt`:
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index 81188ac8cc..17d4a793ac 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -1,3 +1,4 @@
+require 'rack/session/abstract/id'
require 'action_controller/metal/exceptions'
module ActionController #:nodoc:
diff --git a/actionpack/lib/action_dispatch/http/cache.rb b/actionpack/lib/action_dispatch/http/cache.rb
index a7f93b780e..13e2701663 100644
--- a/actionpack/lib/action_dispatch/http/cache.rb
+++ b/actionpack/lib/action_dispatch/http/cache.rb
@@ -17,12 +17,18 @@ module ActionDispatch
env[HTTP_IF_NONE_MATCH]
end
+ def if_none_match_etags
+ (if_none_match ? if_none_match.split(/\s*,\s*/) : []).collect do |etag|
+ etag.gsub(/^\"|\"$/, "")
+ end
+ end
+
def not_modified?(modified_at)
if_modified_since && modified_at && if_modified_since >= modified_at
end
def etag_matches?(etag)
- if_none_match && if_none_match == etag
+ if_none_match_etags.include?(etag)
end
# Check response freshness (Last-Modified and ETag) against request
diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb
index af367ac28d..76f4dea7b8 100644
--- a/actionpack/lib/action_view/lookup_context.rb
+++ b/actionpack/lib/action_view/lookup_context.rb
@@ -149,7 +149,7 @@ module ActionView
# as well as incorrectly putting part of the path in the template
# name instead of the prefix.
def normalize_name(name, prefixes) #:nodoc:
- prefixes = nil if prefixes.blank?
+ prefixes = prefixes.presence
parts = name.to_s.split('/')
parts.shift if parts.first.empty?
name = parts.pop
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index a434e49dbd..a2b9571660 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -746,6 +746,45 @@ class RequestTest < ActiveSupport::TestCase
assert_equal "/foo?bar", path
end
+ test "if_none_match_etags none" do
+ request = stub_request
+
+ assert_equal nil, request.if_none_match
+ assert_equal [], request.if_none_match_etags
+ assert !request.etag_matches?("foo")
+ assert !request.etag_matches?(nil)
+ end
+
+ test "if_none_match_etags single" do
+ header = 'the-etag'
+ request = stub_request('HTTP_IF_NONE_MATCH' => header)
+
+ assert_equal header, request.if_none_match
+ assert_equal [header], request.if_none_match_etags
+ assert request.etag_matches?("the-etag")
+ end
+
+ test "if_none_match_etags quoted single" do
+ header = '"the-etag"'
+ request = stub_request('HTTP_IF_NONE_MATCH' => header)
+
+ assert_equal header, request.if_none_match
+ assert_equal ['the-etag'], request.if_none_match_etags
+ assert request.etag_matches?("the-etag")
+ end
+
+ test "if_none_match_etags multiple" do
+ header = 'etag1, etag2, "third etag", "etag4"'
+ expected = ['etag1', 'etag2', 'third etag', 'etag4']
+ request = stub_request('HTTP_IF_NONE_MATCH' => header)
+
+ assert_equal header, request.if_none_match
+ assert_equal expected, request.if_none_match_etags
+ expected.each do |etag|
+ assert request.etag_matches?(etag), etag
+ end
+ end
+
protected
def stub_request(env = {})
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
index 11e4d34de2..32e3c7f5d8 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -3,8 +3,7 @@ module ActiveRecord
module DatabaseStatements
def initialize
super
- @_current_transaction_records = []
- @transaction_joinable = nil
+ reset_transaction
end
# Converts an arel AST to SQL
@@ -108,20 +107,6 @@ module ActiveRecord
exec_delete(to_sql(arel, binds), name, binds)
end
- # Checks whether there is currently no transaction active. This is done
- # by querying the database driver, and does not use the transaction
- # house-keeping information recorded by #increment_open_transactions and
- # friends.
- #
- # Returns true if there is no transaction active, false if there is a
- # transaction active, and nil if this information is unknown.
- #
- # Not all adapters supports transaction state introspection. Currently,
- # only the PostgreSQL adapter supports this.
- def outside_transaction?
- nil
- end
-
# Returns +true+ when the connection adapter supports prepared statement
# caching, otherwise returns +false+
def supports_statement_cache?
@@ -173,76 +158,60 @@ module ActiveRecord
def transaction(options = {})
options.assert_valid_keys :requires_new, :joinable
- last_transaction_joinable = @transaction_joinable
- @transaction_joinable = options.fetch(:joinable, true)
- requires_new = options[:requires_new] || !last_transaction_joinable
- transaction_open = false
-
- begin
- if requires_new || open_transactions == 0
- if open_transactions == 0
- begin_db_transaction
- elsif requires_new
- create_savepoint
- end
- increment_open_transactions
- transaction_open = true
- @_current_transaction_records.push([])
- end
+ if !options[:requires_new] && current_transaction.joinable?
yield
- rescue Exception => database_transaction_rollback
- if transaction_open && !outside_transaction?
- transaction_open = false
- txn = decrement_open_transactions
- txn.aborted!
- if open_transactions == 0
- rollback_db_transaction
- rollback_transaction_records(true)
- else
- rollback_to_savepoint
- rollback_transaction_records(false)
- end
- end
- raise unless database_transaction_rollback.is_a?(ActiveRecord::Rollback)
+ else
+ within_new_transaction(options) { yield }
end
+ rescue ActiveRecord::Rollback
+ # rollbacks are silently swallowed
+ end
+
+ def within_new_transaction(options = {}) #:nodoc:
+ begin_transaction(options)
+ yield
+ rescue Exception => error
+ rollback_transaction
+ raise
ensure
- @transaction_joinable = last_transaction_joinable
-
- if outside_transaction?
- @current_transaction = nil
- elsif transaction_open
- txn = decrement_open_transactions
- txn.committed!
- begin
- if open_transactions == 0
- commit_db_transaction
- commit_transaction_records
- else
- release_savepoint
- save_point_records = @_current_transaction_records.pop
- unless save_point_records.blank?
- @_current_transaction_records.push([]) if @_current_transaction_records.empty?
- @_current_transaction_records.last.concat(save_point_records)
- end
- end
- rescue Exception
- if open_transactions == 0
- rollback_db_transaction
- rollback_transaction_records(true)
- else
- rollback_to_savepoint
- rollback_transaction_records(false)
- end
- raise
- end
+ begin
+ commit_transaction unless error
+ rescue Exception
+ rollback_transaction
+ raise
end
end
+ def current_transaction #:nodoc:
+ @transaction
+ end
+
+ def transaction_open?
+ @transaction.open?
+ end
+
+ def begin_transaction(options = {}) #:nodoc:
+ @transaction = @transaction.begin
+ @transaction.joinable = options.fetch(:joinable, true)
+ @transaction
+ end
+
+ def commit_transaction #:nodoc:
+ @transaction = @transaction.commit
+ end
+
+ def rollback_transaction #:nodoc:
+ @transaction = @transaction.rollback
+ end
+
+ def reset_transaction #:nodoc:
+ @transaction = ClosedTransaction.new(self)
+ end
+
# Register a record with the current transaction so that its after_commit and after_rollback callbacks
# can be called.
def add_transaction_record(record)
- last_batch = @_current_transaction_records.last
- last_batch << record if last_batch
+ @transaction.add_record(record)
end
# Begins the transaction (and turns off auto-committing).
@@ -356,42 +325,6 @@ module ActiveRecord
update_sql(sql, name)
end
- # Send a rollback message to all records after they have been rolled back. If rollback
- # is false, only rollback records since the last save point.
- def rollback_transaction_records(rollback)
- if rollback
- records = @_current_transaction_records.flatten
- @_current_transaction_records.clear
- else
- records = @_current_transaction_records.pop
- end
-
- unless records.blank?
- records.uniq.each do |record|
- begin
- record.rolledback!(rollback)
- rescue => e
- record.logger.error(e) if record.respond_to?(:logger) && record.logger
- end
- end
- end
- end
-
- # Send a commit message to all records after they have been committed.
- def commit_transaction_records
- records = @_current_transaction_records.flatten
- @_current_transaction_records.clear
- unless records.blank?
- records.uniq.each do |record|
- begin
- record.committed!
- rescue => e
- record.logger.error(e) if record.respond_to?(:logger) && record.logger
- end
- end
- end
- end
-
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
[sql, binds]
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb
new file mode 100644
index 0000000000..2117eae5cb
--- /dev/null
+++ b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb
@@ -0,0 +1,156 @@
+module ActiveRecord
+ module ConnectionAdapters
+ class Transaction #:nodoc:
+ attr_reader :connection
+
+ def initialize(connection)
+ @connection = connection
+ end
+ end
+
+ class ClosedTransaction < Transaction #:nodoc:
+ def number
+ 0
+ end
+
+ def begin
+ RealTransaction.new(connection, self)
+ end
+
+ def closed?
+ true
+ end
+
+ def open?
+ false
+ end
+
+ def joinable?
+ false
+ end
+
+ # This is a noop when there are no open transactions
+ def add_record(record)
+ end
+ end
+
+ class OpenTransaction < Transaction #:nodoc:
+ attr_reader :parent, :records
+ attr_writer :joinable
+
+ def initialize(connection, parent)
+ super connection
+
+ @parent = parent
+ @records = []
+ @finishing = false
+ @joinable = true
+ end
+
+ # This state is necesarry so that we correctly handle stuff that might
+ # happen in a commit/rollback. But it's kinda distasteful. Maybe we can
+ # find a better way to structure it in the future.
+ def finishing?
+ @finishing
+ end
+
+ def joinable?
+ @joinable && !finishing?
+ end
+
+ def number
+ if finishing?
+ parent.number
+ else
+ parent.number + 1
+ end
+ end
+
+ def begin
+ if finishing?
+ parent.begin
+ else
+ SavepointTransaction.new(connection, self)
+ end
+ end
+
+ def rollback
+ @finishing = true
+ perform_rollback
+ parent
+ end
+
+ def commit
+ @finishing = true
+ perform_commit
+ parent
+ end
+
+ def add_record(record)
+ records << record
+ end
+
+ def rollback_records
+ records.uniq.each do |record|
+ begin
+ record.rolledback!(parent.closed?)
+ rescue => e
+ record.logger.error(e) if record.respond_to?(:logger) && record.logger
+ end
+ end
+ end
+
+ def commit_records
+ records.uniq.each do |record|
+ begin
+ record.committed!
+ rescue => e
+ record.logger.error(e) if record.respond_to?(:logger) && record.logger
+ end
+ end
+ end
+
+ def closed?
+ false
+ end
+
+ def open?
+ true
+ end
+ end
+
+ class RealTransaction < OpenTransaction #:nodoc:
+ def initialize(connection, parent)
+ super
+ connection.begin_db_transaction
+ end
+
+ def perform_rollback
+ connection.rollback_db_transaction
+ rollback_records
+ end
+
+ def perform_commit
+ connection.commit_db_transaction
+ commit_records
+ end
+ end
+
+ class SavepointTransaction < OpenTransaction #:nodoc:
+ def initialize(connection, parent)
+ super
+ connection.create_savepoint
+ end
+
+ def perform_rollback
+ connection.rollback_to_savepoint
+ rollback_records
+ end
+
+ def perform_commit
+ connection.release_savepoint
+ records.each { |r| parent.add_record(r) }
+ end
+ end
+ end
+end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 27700e4fd2..c37c9b1ae1 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -4,6 +4,7 @@ require 'bigdecimal/util'
require 'active_support/core_ext/benchmark'
require 'active_record/connection_adapters/schema_cache'
require 'monitor'
+require 'active_support/deprecation'
module ActiveRecord
module ConnectionAdapters # :nodoc:
@@ -33,6 +34,12 @@ module ActiveRecord
autoload :QueryCache
end
+ autoload_at 'active_record/connection_adapters/abstract/transaction' do
+ autoload :ClosedTransaction
+ autoload :RealTransaction
+ autoload :SavepointTransaction
+ end
+
# Active Record supports multiple database systems. AbstractAdapter and
# related classes form the abstraction layer which makes this possible.
# An AbstractAdapter represents a connection to a database, and provides an
@@ -62,14 +69,11 @@ module ActiveRecord
def initialize(connection, logger = nil, pool = nil) #:nodoc:
super()
- @active = nil
@connection = connection
@in_use = false
@instrumenter = ActiveSupport::Notifications.instrumenter
@last_use = false
@logger = logger
- @open_transactions = 0
- @current_transaction = nil
@pool = pool
@query_cache = Hash.new { |h,sql| h[sql] = {} }
@query_cache_enabled = false
@@ -182,19 +186,21 @@ module ActiveRecord
# checking whether the database is actually capable of responding, i.e. whether
# the connection isn't stale.
def active?
- @active != false
end
# Disconnects from the database if already connected, and establishes a
- # new connection with the database.
+ # new connection with the database. Implementors should call super if they
+ # override the default implementation.
def reconnect!
- @active = true
+ clear_cache!
+ reset_transaction
end
# Disconnects from the database if already connected. Otherwise, this
# method does nothing.
def disconnect!
- @active = false
+ clear_cache!
+ reset_transaction
end
# Reset the state of this connection, directing the DBMS to clear
@@ -238,33 +244,20 @@ module ActiveRecord
end
def open_transactions
- count = 0
- txn = current_transaction
-
- while txn
- count += 1
- txn = txn.next
- end
-
- count
+ @transaction.number
end
- attr_reader :current_transaction
-
def increment_open_transactions
- @current_transaction = Transaction.new(current_transaction)
+ ActiveSupport::Deprecation.warn "#increment_open_transactions is deprecated and has no effect"
end
def decrement_open_transactions
- return unless current_transaction
-
- txn = current_transaction
- @current_transaction = txn.next
- txn
+ ActiveSupport::Deprecation.warn "#decrement_open_transactions is deprecated and has no effect"
end
def transaction_joinable=(joinable)
- @transaction_joinable = joinable
+ ActiveSupport::Deprecation.warn "#transaction_joinable= is deprecated. Please pass the :joinable option to #begin_transaction instead."
+ @transaction.joinable = joinable
end
def create_savepoint
diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
index 8fc172f6e8..328d080687 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
@@ -74,6 +74,7 @@ module ActiveRecord
end
def reconnect!
+ super
disconnect!
connect
end
@@ -82,6 +83,7 @@ module ActiveRecord
# Disconnects from the database if already connected.
# Otherwise, this method does nothing.
def disconnect!
+ super
unless @connection.nil?
@connection.close
@connection = nil
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index bb63fddf9b..0b936bbf39 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -189,14 +189,15 @@ module ActiveRecord
end
def reconnect!
+ super
disconnect!
- clear_cache!
connect
end
# Disconnects from the database if already connected. Otherwise, this
# method does nothing.
def disconnect!
+ super
@connection.close rescue nil
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb
index eb3084e066..c8437c18cc 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb
@@ -1,3 +1,5 @@
+require 'active_support/deprecation'
+
module ActiveRecord
module ConnectionAdapters
class PostgreSQLAdapter < AbstractAdapter
@@ -214,6 +216,10 @@ module ActiveRecord
end
def outside_transaction?
+ ActiveSupport::Deprecation.warn(
+ "#outside_transaction? is deprecated. This method was only really used " \
+ "internally, but you can use #transaction_open? instead."
+ )
@connection.transaction_status == PGconn::PQTRANS_IDLE
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index d1751d70c6..e85e63d607 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -431,9 +431,8 @@ module ActiveRecord
# Close then reopen the connection.
def reconnect!
- clear_cache!
+ super
@connection.reset
- @open_transactions = 0
configure_connection
end
@@ -445,7 +444,7 @@ module ActiveRecord
# Disconnects from the database if already connected. Otherwise, this
# method does nothing.
def disconnect!
- clear_cache!
+ super
@connection.close rescue nil
end
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index 4fe0013f0f..b6dd2e17f4 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -104,6 +104,8 @@ module ActiveRecord
def initialize(connection, logger, config)
super(connection, logger)
+
+ @active = nil
@statements = StatementPool.new(@connection,
config.fetch(:statement_limit) { 1000 })
@config = config
@@ -154,11 +156,15 @@ module ActiveRecord
true
end
+ def active?
+ @active != false
+ end
+
# Disconnects from the database if already connected. Otherwise, this
# method does nothing.
def disconnect!
super
- clear_cache!
+ @active = false
@connection.close rescue nil
end
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index cf64985ddb..43ffca0227 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -387,7 +387,6 @@ module ActiveRecord
@marked_for_destruction = false
@new_record = true
@mass_assignment_options = nil
- @txn = nil
@_start_transaction_state = {}
end
end
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index b1db5f6f9f..60fc653735 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -843,9 +843,7 @@ module ActiveRecord
end
@fixture_connections = enlist_fixture_connections
@fixture_connections.each do |connection|
- connection.increment_open_transactions
- connection.transaction_joinable = false
- connection.begin_db_transaction
+ connection.begin_transaction joinable: false
end
# Load fixtures for every test.
else
@@ -868,10 +866,7 @@ module ActiveRecord
# Rollback changes if a transaction is active.
if run_in_transaction?
@fixture_connections.each do |connection|
- if connection.open_transactions != 0
- connection.rollback_db_transaction
- connection.decrement_open_transactions
- end
+ connection.rollback_transaction if connection.transaction_open?
end
@fixture_connections.clear
end
diff --git a/activerecord/lib/active_record/railties/console_sandbox.rb b/activerecord/lib/active_record/railties/console_sandbox.rb
index 65a3d68619..90b462fad6 100644
--- a/activerecord/lib/active_record/railties/console_sandbox.rb
+++ b/activerecord/lib/active_record/railties/console_sandbox.rb
@@ -1,6 +1,4 @@
-ActiveRecord::Base.connection.increment_open_transactions
ActiveRecord::Base.connection.begin_db_transaction
at_exit do
ActiveRecord::Base.connection.rollback_db_transaction
- ActiveRecord::Base.connection.decrement_open_transactions
end
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index e008b32170..09318879d5 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -1,32 +1,6 @@
require 'thread'
module ActiveRecord
- class Transaction
- attr_reader :next
-
- def initialize(txn = nil)
- @next = txn
- @committed = false
- @aborted = false
- end
-
- def committed!
- @committed = true
- end
-
- def aborted!
- @aborted = true
- end
-
- def committed?
- @committed
- end
-
- def aborted?
- @aborted
- end
- end
-
# See ActiveRecord::Transactions::ClassMethods for documentation.
module Transactions
extend ActiveSupport::Concern
@@ -333,11 +307,11 @@ module ActiveRecord
def with_transaction_returning_status
status = nil
self.class.transaction do
- @txn = self.class.connection.current_transaction
add_to_transaction
begin
status = yield
rescue ActiveRecord::Rollback
+ @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
status = nil
end
@@ -353,17 +327,20 @@ module ActiveRecord
@_start_transaction_state[:id] = id if has_attribute?(self.class.primary_key)
@_start_transaction_state[:new_record] = @new_record
@_start_transaction_state[:destroyed] = @destroyed
+ @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) + 1
end
# Clear the new record state and id of a record.
def clear_transaction_record_state #:nodoc:
- @_start_transaction_state.clear if @txn.committed?
+ @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
+ @_start_transaction_state.clear if @_start_transaction_state[:level] < 1
end
# Restore the new record state and id of a record that was previously saved by a call to save_record_state.
def restore_transaction_record_state(force = false) #:nodoc:
unless @_start_transaction_state.empty?
- if @txn.aborted? || force
+ @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
+ if @_start_transaction_state[:level] < 1 || force
restore_state = @_start_transaction_state
was_frozen = @attributes.frozen?
@attributes = @attributes.dup if was_frozen
diff --git a/activerecord/test/active_record/connection_adapters/fake_adapter.rb b/activerecord/test/active_record/connection_adapters/fake_adapter.rb
index 1199be68eb..59324c4857 100644
--- a/activerecord/test/active_record/connection_adapters/fake_adapter.rb
+++ b/activerecord/test/active_record/connection_adapters/fake_adapter.rb
@@ -36,6 +36,10 @@ module ActiveRecord
def columns(table_name)
@columns[table_name]
end
+
+ def active?
+ true
+ end
end
end
end
diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb
index 852fc0e26e..93b01a3934 100644
--- a/activerecord/test/cases/adapter_test.rb
+++ b/activerecord/test/cases/adapter_test.rb
@@ -160,4 +160,36 @@ module ActiveRecord
end
end
end
+
+ class AdapterTestWithoutTransaction < ActiveRecord::TestCase
+ self.use_transactional_fixtures = false
+
+ def setup
+ @klass = Class.new(ActiveRecord::Base)
+ @klass.establish_connection 'arunit'
+ @connection = @klass.connection
+ end
+
+ def teardown
+ @klass.remove_connection
+ end
+
+ test "transaction state is reset after a reconnect" do
+ skip "in-memory db doesn't allow reconnect" if in_memory_db?
+
+ @connection.begin_transaction
+ assert @connection.transaction_open?
+ @connection.reconnect!
+ assert !@connection.transaction_open?
+ end
+
+ test "transaction state is reset after a disconnect" do
+ skip "in-memory db doesn't allow disconnect" if in_memory_db?
+
+ @connection.begin_transaction
+ assert @connection.transaction_open?
+ @connection.disconnect!
+ assert !@connection.transaction_open?
+ end
+ end
end
diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb
index 0d0de455b3..0b5fda3817 100644
--- a/activerecord/test/cases/transactions_test.rb
+++ b/activerecord/test/cases/transactions_test.rb
@@ -36,6 +36,7 @@ class TransactionTest < ActiveRecord::TestCase
end
end
+ # FIXME: Get rid of this fucking global variable!
def test_successful_with_return
class << Topic.connection
alias :real_commit_db_transaction :commit_db_transaction
@@ -348,7 +349,6 @@ class TransactionTest < ActiveRecord::TestCase
def test_rollback_when_commit_raises
Topic.connection.expects(:begin_db_transaction)
Topic.connection.expects(:commit_db_transaction).raises('OH NOES')
- Topic.connection.expects(:outside_transaction?).returns(false)
Topic.connection.expects(:rollback_db_transaction)
assert_raise RuntimeError do
@@ -397,31 +397,11 @@ class TransactionTest < ActiveRecord::TestCase
if current_adapter?(:PostgreSQLAdapter) && defined?(PGconn::PQTRANS_IDLE)
def test_outside_transaction_works
- assert Topic.connection.outside_transaction?
+ assert assert_deprecated { Topic.connection.outside_transaction? }
Topic.connection.begin_db_transaction
- assert !Topic.connection.outside_transaction?
+ assert assert_deprecated { !Topic.connection.outside_transaction? }
Topic.connection.rollback_db_transaction
- assert Topic.connection.outside_transaction?
- end
-
- def test_rollback_wont_be_executed_if_no_transaction_active
- assert_raise RuntimeError do
- Topic.transaction do
- Topic.connection.rollback_db_transaction
- Topic.connection.expects(:rollback_db_transaction).never
- raise "Rails doesn't scale!"
- end
- end
- end
-
- def test_open_transactions_count_is_reset_to_zero_if_no_transaction_active
- Topic.transaction do
- Topic.transaction do
- Topic.connection.rollback_db_transaction
- end
- assert_equal 0, Topic.connection.open_transactions
- end
- assert_equal 0, Topic.connection.open_transactions
+ assert assert_deprecated { Topic.connection.outside_transaction? }
end
end
@@ -580,5 +560,14 @@ if current_adapter?(:PostgreSQLAdapter)
assert_equal original_salary, Developer.find(1).salary
end
+
+ test "#transaction_joinable= is deprecated" do
+ Developer.transaction do
+ conn = Developer.connection
+ assert conn.current_transaction.joinable?
+ assert_deprecated { conn.transaction_joinable = false }
+ assert !conn.current_transaction.joinable?
+ end
+ end
end
end
diff --git a/activesupport/lib/active_support/core_ext/object/to_json.rb b/activesupport/lib/active_support/core_ext/object/to_json.rb
index e7dc60a612..83cc8066e7 100644
--- a/activesupport/lib/active_support/core_ext/object/to_json.rb
+++ b/activesupport/lib/active_support/core_ext/object/to_json.rb
@@ -17,3 +17,11 @@ end
end
end
end
+
+module Process
+ class Status
+ def as_json(options = nil)
+ { :exitstatus => exitstatus, :pid => pid }
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/deprecation/reporting.rb b/activesupport/lib/active_support/deprecation/reporting.rb
index 02e8ff7c87..43a4ed81e5 100644
--- a/activesupport/lib/active_support/deprecation/reporting.rb
+++ b/activesupport/lib/active_support/deprecation/reporting.rb
@@ -35,8 +35,8 @@ module ActiveSupport
end
def deprecation_warning(deprecated_method_name, message = nil, caller_backtrace = caller)
- deprecated_method_warning(deprecated_method_name, message).tap do |message|
- warn(message, caller_backtrace)
+ deprecated_method_warning(deprecated_method_name, message).tap do |msg|
+ warn(msg, caller_backtrace)
end
end
diff --git a/activesupport/lib/active_support/queueing.rb b/activesupport/lib/active_support/queueing.rb
new file mode 100644
index 0000000000..f397e1c0c5
--- /dev/null
+++ b/activesupport/lib/active_support/queueing.rb
@@ -0,0 +1,116 @@
+require 'delegate'
+require 'thread'
+
+module ActiveSupport
+ # A Queue that simply inherits from STDLIB's Queue. Everytime this
+ # queue is used, Rails automatically sets up a ThreadedConsumer
+ # to consume it.
+ class Queue < ::Queue
+ end
+
+ class SynchronousQueue < ::Queue
+ def push(job)
+ result = nil
+ Thread.new { result = job.run }.join
+ result
+ end
+ alias << push
+ alias enq push
+ end
+
+ # In test mode, the Rails queue is backed by an Array so that assertions
+ # can be made about its contents. The test queue provides a +jobs+
+ # method to make assertions about the queue's contents and a +drain+
+ # method to drain the queue and run the jobs.
+ #
+ # Jobs are run in a separate thread to catch mistakes where code
+ # assumes that the job is run in the same thread.
+ class TestQueue < ::Queue
+ # Get a list of the jobs off this queue. This method may not be
+ # available on production queues.
+ def jobs
+ @que.dup
+ end
+
+ # Marshal and unmarshal job before pushing it onto the queue. This will
+ # raise an exception on any attempts in tests to push jobs that can't (or
+ # shouldn't) be marshalled.
+ def push(job)
+ super Marshal.load(Marshal.dump(job))
+ end
+
+ # Drain the queue, running all jobs in a different thread. This method
+ # may not be available on production queues.
+ def drain
+ # run the jobs in a separate thread so assumptions of synchronous
+ # jobs are caught in test mode.
+ Thread.new { pop.run until empty? }.join
+ end
+ end
+
+ # A container for multiple queues. This class delegates to a default Queue
+ # so that <tt>Rails.queue.push</tt> and friends will Just Work. To use this class
+ # with multiple queues:
+ #
+ # # In your configuration:
+ # Rails.queue[:image_queue] = SomeQueue.new
+ # Rails.queue[:mail_queue] = SomeQueue.new
+ #
+ # # In your app code:
+ # Rails.queue[:mail_queue].push SomeJob.new
+ #
+ class QueueContainer < DelegateClass(::Queue)
+ def initialize(default_queue)
+ @queues = { :default => default_queue }
+ super(default_queue)
+ end
+
+ def [](queue_name)
+ @queues[queue_name]
+ end
+
+ def []=(queue_name, queue)
+ @queues[queue_name] = queue
+ end
+ end
+
+ # The threaded consumer will run jobs in a background thread in
+ # development mode or in a VM where running jobs on a thread in
+ # production mode makes sense.
+ #
+ # When the process exits, the consumer pushes a nil onto the
+ # queue and joins the thread, which will ensure that all jobs
+ # are executed before the process finally dies.
+ class ThreadedQueueConsumer
+ def self.start(queue, logger=nil)
+ new(queue, logger).start
+ end
+
+ def initialize(queue, logger=nil)
+ @queue = queue
+ @logger = logger
+ end
+
+ def start
+ @thread = Thread.new do
+ while job = @queue.pop
+ begin
+ job.run
+ rescue Exception => e
+ handle_exception e
+ end
+ end
+ end
+ self
+ end
+
+ def shutdown
+ @queue.push nil
+ @thread.join
+ end
+
+ def handle_exception(e)
+ @logger.error "Job Error: #{e.message}\n#{e.backtrace.join("\n")}" if @logger
+ end
+ end
+end
diff --git a/activesupport/test/queueing/container_test.rb b/activesupport/test/queueing/container_test.rb
new file mode 100644
index 0000000000..7afc11e7a9
--- /dev/null
+++ b/activesupport/test/queueing/container_test.rb
@@ -0,0 +1,28 @@
+require 'abstract_unit'
+require 'active_support/queueing'
+
+module ActiveSupport
+ class ContainerTest < ActiveSupport::TestCase
+ def test_delegates_to_default
+ q = Queue.new
+ container = QueueContainer.new q
+ job = Object.new
+
+ container.push job
+ assert_equal job, q.pop
+ end
+
+ def test_access_default
+ q = Queue.new
+ container = QueueContainer.new q
+ assert_equal q, container[:default]
+ end
+
+ def test_assign_queue
+ container = QueueContainer.new Object.new
+ q = Object.new
+ container[:foo] = q
+ assert_equal q, container[:foo]
+ end
+ end
+end
diff --git a/railties/test/queueing/test_queue_test.rb b/activesupport/test/queueing/test_queue_test.rb
index 2f0f507adb..4c08314366 100644
--- a/railties/test/queueing/test_queue_test.rb
+++ b/activesupport/test/queueing/test_queue_test.rb
@@ -1,9 +1,9 @@
require 'abstract_unit'
-require 'rails/queueing'
+require 'active_support/queueing'
class TestQueueTest < ActiveSupport::TestCase
def setup
- @queue = Rails::Queueing::TestQueue.new
+ @queue = ActiveSupport::TestQueue.new
end
class ExceptionRaisingJob
diff --git a/railties/test/queueing/threaded_consumer_test.rb b/activesupport/test/queueing/threaded_consumer_test.rb
index c34a966d6e..20a1cc4e8e 100644
--- a/railties/test/queueing/threaded_consumer_test.rb
+++ b/activesupport/test/queueing/threaded_consumer_test.rb
@@ -1,5 +1,6 @@
require 'abstract_unit'
-require 'rails/queueing'
+require 'active_support/queueing'
+require "active_support/log_subscriber/test_helper"
class TestThreadConsumer < ActiveSupport::TestCase
class Job
@@ -15,8 +16,9 @@ class TestThreadConsumer < ActiveSupport::TestCase
end
def setup
- @queue = Rails::Queueing::Queue.new
- @consumer = Rails::Queueing::ThreadedConsumer.start(@queue)
+ @queue = ActiveSupport::Queue.new
+ @logger = ActiveSupport::LogSubscriber::TestHelper::MockLogger.new
+ @consumer = ActiveSupport::ThreadedQueueConsumer.start(@queue, @logger)
end
def teardown
@@ -64,10 +66,6 @@ class TestThreadConsumer < ActiveSupport::TestCase
end
test "log job that raises an exception" do
- require "active_support/log_subscriber/test_helper"
- logger = ActiveSupport::LogSubscriber::TestHelper::MockLogger.new
- Rails.logger = logger
-
job = Job.new(1) do
raise "RuntimeError: Error!"
end
@@ -75,13 +73,13 @@ class TestThreadConsumer < ActiveSupport::TestCase
@queue.push job
sleep 0.1
- assert_equal 1, logger.logged(:error).size
- assert_match(/Job Error: RuntimeError: Error!/, logger.logged(:error).last)
+ assert_equal 1, @logger.logged(:error).size
+ assert_match(/Job Error: RuntimeError: Error!/, @logger.logged(:error).last)
end
test "test overriding exception handling" do
@consumer.shutdown
- @consumer = Class.new(Rails::Queueing::ThreadedConsumer) do
+ @consumer = Class.new(ActiveSupport::ThreadedQueueConsumer) do
attr_reader :last_error
def handle_exception(e)
@last_error = e.message
diff --git a/guides/source/configuring.textile b/guides/source/configuring.textile
index 73d6102eac..9c35738bf8 100644
--- a/guides/source/configuring.textile
+++ b/guides/source/configuring.textile
@@ -111,9 +111,9 @@ end
* +config.middleware+ allows you to configure the application's middleware. This is covered in depth in the "Configuring Middleware":#configuring-middleware section below.
-* +config.queue+ configures a different queue implementation for the application. Defaults to +Rails::Queueing::Queue+. Note that, if the default queue is changed, the default +queue_consumer+ is not going to be initialized, it is up to the new queue implementation to handle starting and shutting down its own consumer(s).
+* +config.queue+ configures a different queue implementation for the application. Defaults to +ActiveSupport::SynchronousQueue+. Note that, if the default queue is changed, the default +queue_consumer+ is not going to be initialized, it is up to the new queue implementation to handle starting and shutting down its own consumer(s).
-* +config.queue_consumer+ configures a different consumer implementation for the default queue. Defaults to +Rails::Queueing::ThreadedConsumer+.
+* +config.queue_consumer+ configures a different consumer implementation for the default queue. Defaults to +ActiveSupport::ThreadedQueueConsumer+.
* +config.reload_classes_only_on_change+ enables or disables reloading of classes only when tracked files change. By default tracks everything on autoload paths and is set to true. If +config.cache_classes+ is true, this option is ignored.
diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb
index 670477f91a..a15965a9da 100644
--- a/railties/lib/rails.rb
+++ b/railties/lib/rails.rb
@@ -22,7 +22,6 @@ end
module Rails
autoload :Info, 'rails/info'
autoload :InfoController, 'rails/info_controller'
- autoload :Queueing, 'rails/queueing'
class << self
def application
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index 80b8e4b9ba..aa5b986862 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -1,4 +1,5 @@
require 'fileutils'
+require 'active_support/queueing'
require 'rails/engine'
module Rails
@@ -188,7 +189,7 @@ module Rails
end
def queue #:nodoc:
- @queue ||= Queueing::Container.new(build_queue)
+ @queue ||= ActiveSupport::QueueContainer.new(build_queue)
end
def build_queue #:nodoc:
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index 7a0bb21043..c4c1fcca40 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/kernel/reporting'
require 'active_support/file_update_checker'
+require 'active_support/queueing'
require 'rails/engine/configuration'
module Rails
@@ -41,8 +42,8 @@ module Rails
@exceptions_app = nil
@autoflush_log = true
@log_formatter = ActiveSupport::Logger::SimpleFormatter.new
- @queue = Rails::Queueing::SynchronousQueue
- @queue_consumer = Rails::Queueing::ThreadedConsumer
+ @queue = ActiveSupport::SynchronousQueue
+ @queue_consumer = ActiveSupport::ThreadedQueueConsumer
@eager_load = nil
@assets = ActiveSupport::OrderedOptions.new
diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb
index 777f0d269e..f9a3c00946 100644
--- a/railties/lib/rails/application/finisher.rb
+++ b/railties/lib/rails/application/finisher.rb
@@ -97,8 +97,8 @@ module Rails
end
initializer :activate_queue_consumer do |app|
- if config.queue == Rails::Queueing::Queue
- app.queue_consumer = config.queue_consumer.start(app.queue)
+ if config.queue == ActiveSupport::Queue
+ app.queue_consumer = config.queue_consumer.start(app.queue, Rails.logger)
at_exit { app.queue_consumer.shutdown }
end
end
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
index fdf011a510..cb3e8b123e 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
@@ -82,5 +82,5 @@
# Default the production mode queue to an synchronous queue. You will probably
# want to replace this with an out-of-process queueing solution.
- # config.queue = Rails::Queueing::SynchronousQueue
+ # config.queue = ActiveSupport::SynchronousQueue
end
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
index 8ab27eb6e1..75897ba8cd 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
@@ -40,5 +40,5 @@
config.active_support.deprecation = :stderr
# Use the testing queue.
- config.queue = Rails::Queueing::TestQueue
+ config.queue = ActiveSupport::TestQueue
end
diff --git a/railties/lib/rails/queueing.rb b/railties/lib/rails/queueing.rb
deleted file mode 100644
index 7cd755b0f7..0000000000
--- a/railties/lib/rails/queueing.rb
+++ /dev/null
@@ -1,115 +0,0 @@
-require "thread"
-require 'delegate'
-
-module Rails
- module Queueing
- # A container for multiple queues. This class delegates to a default Queue
- # so that <tt>Rails.queue.push</tt> and friends will Just Work. To use this class
- # with multiple queues:
- #
- # # In your configuration:
- # Rails.queue[:image_queue] = SomeQueue.new
- # Rails.queue[:mail_queue] = SomeQueue.new
- #
- # # In your app code:
- # Rails.queue[:mail_queue].push SomeJob.new
- #
- class Container < DelegateClass(::Queue)
- def initialize(default_queue)
- @queues = { :default => default_queue }
- super(default_queue)
- end
-
- def [](queue_name)
- @queues[queue_name]
- end
-
- def []=(queue_name, queue)
- @queues[queue_name] = queue
- end
- end
-
- # A Queue that simply inherits from STDLIB's Queue. Everytime this
- # queue is used, Rails automatically sets up a ThreadedConsumer
- # to consume it.
- class Queue < ::Queue
- end
-
- class SynchronousQueue < ::Queue
- def push(job)
- job.run
- end
- alias << push
- alias enq push
- end
-
- # In test mode, the Rails queue is backed by an Array so that assertions
- # can be made about its contents. The test queue provides a +jobs+
- # method to make assertions about the queue's contents and a +drain+
- # method to drain the queue and run the jobs.
- #
- # Jobs are run in a separate thread to catch mistakes where code
- # assumes that the job is run in the same thread.
- class TestQueue < ::Queue
- # Get a list of the jobs off this queue. This method may not be
- # available on production queues.
- def jobs
- @que.dup
- end
-
- # Marshal and unmarshal job before pushing it onto the queue. This will
- # raise an exception on any attempts in tests to push jobs that can't (or
- # shouldn't) be marshalled.
- def push(job)
- super Marshal.load(Marshal.dump(job))
- end
-
- # Drain the queue, running all jobs in a different thread. This method
- # may not be available on production queues.
- def drain
- # run the jobs in a separate thread so assumptions of synchronous
- # jobs are caught in test mode.
- Thread.new { pop.run until empty? }.join
- end
- end
-
- # The threaded consumer will run jobs in a background thread in
- # development mode or in a VM where running jobs on a thread in
- # production mode makes sense.
- #
- # When the process exits, the consumer pushes a nil onto the
- # queue and joins the thread, which will ensure that all jobs
- # are executed before the process finally dies.
- class ThreadedConsumer
- def self.start(queue)
- new(queue).start
- end
-
- def initialize(queue)
- @queue = queue
- end
-
- def start
- @thread = Thread.new do
- while job = @queue.pop
- begin
- job.run
- rescue Exception => e
- handle_exception e
- end
- end
- end
- self
- end
-
- def shutdown
- @queue.push nil
- @thread.join
- end
-
- def handle_exception(e)
- Rails.logger.error "Job Error: #{e.message}\n#{e.backtrace.join("\n")}"
- end
- end
- end
-end
diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb
index 1eb5fce384..5268257d62 100644
--- a/railties/test/application/initializers/frameworks_test.rb
+++ b/railties/test/application/initializers/frameworks_test.rb
@@ -52,19 +52,19 @@ module ApplicationTests
test "uses the default queue for ActionMailer" do
require "#{app_path}/config/environment"
- assert_kind_of Rails::Queueing::Container, ActionMailer::Base.queue
+ assert_kind_of ActiveSupport::QueueContainer, ActionMailer::Base.queue
end
test "allows me to configure queue for ActionMailer" do
app_file "config/environments/development.rb", <<-RUBY
AppTemplate::Application.configure do
- Rails.queue[:mailer] = Rails::Queueing::TestQueue.new
+ Rails.queue[:mailer] = ActiveSupport::TestQueue.new
config.action_mailer.queue = Rails.queue[:mailer]
end
RUBY
require "#{app_path}/config/environment"
- assert_kind_of Rails::Queueing::TestQueue, ActionMailer::Base.queue
+ assert_kind_of ActiveSupport::TestQueue, ActionMailer::Base.queue
end
test "does not include url helpers as action methods" do
diff --git a/railties/test/application/queue_test.rb b/railties/test/application/queue_test.rb
index f4c11c5f4f..664001ca69 100644
--- a/railties/test/application/queue_test.rb
+++ b/railties/test/application/queue_test.rb
@@ -19,14 +19,14 @@ module ApplicationTests
test "the queue is a TestQueue in test mode" do
app("test")
- assert_kind_of Rails::Queueing::TestQueue, Rails.application.queue[:default]
- assert_kind_of Rails::Queueing::TestQueue, Rails.queue[:default]
+ assert_kind_of ActiveSupport::TestQueue, Rails.application.queue[:default]
+ assert_kind_of ActiveSupport::TestQueue, Rails.queue[:default]
end
test "the queue is a SynchronousQueue in development mode" do
app("development")
- assert_kind_of Rails::Queueing::SynchronousQueue, Rails.application.queue[:default]
- assert_kind_of Rails::Queueing::SynchronousQueue, Rails.queue[:default]
+ assert_kind_of ActiveSupport::SynchronousQueue, Rails.application.queue[:default]
+ assert_kind_of ActiveSupport::SynchronousQueue, Rails.queue[:default]
end
class ThreadTrackingJob
@@ -47,7 +47,7 @@ module ApplicationTests
end
end
- test "in development mode, an enqueued job will be processed in the same thread" do
+ test "in development mode, an enqueued job will be processed in a separate thread" do
app("development")
job = ThreadTrackingJob.new
@@ -55,7 +55,7 @@ module ApplicationTests
sleep 0.1
assert job.ran?, "Expected job to be run"
- refute job.ran_in_different_thread?, "Expected job to run in the same thread"
+ assert job.ran_in_different_thread?, "Expected job to run in the same thread"
end
test "in test mode, explicitly draining the queue will process it in a separate thread" do
@@ -160,12 +160,12 @@ module ApplicationTests
test "a custom consumer implementation can be provided" do
add_to_env_config "production", <<-RUBY
require "my_queue_consumer"
- config.queue = Rails::Queueing::Queue
+ config.queue = ActiveSupport::Queue
config.queue_consumer = MyQueueConsumer
RUBY
app_file "lib/my_queue_consumer.rb", <<-RUBY
- class MyQueueConsumer < Rails::Queueing::ThreadedConsumer
+ class MyQueueConsumer < ActiveSupport::ThreadedQueueConsumer
attr_reader :started
def start
diff --git a/railties/test/application/rake/dbs_test.rb b/railties/test/application/rake/dbs_test.rb
index 52c07cee9f..03798d572a 100644
--- a/railties/test/application/rake/dbs_test.rb
+++ b/railties/test/application/rake/dbs_test.rb
@@ -100,8 +100,8 @@ module ApplicationTests
`rails generate model book title:string`
`bundle exec rake db:migrate`
`bundle exec rake db:fixtures:load`
- assert_match /#{expected[:database]}/,
- ActiveRecord::Base.connection_config[:database]
+ assert_match(/#{expected[:database]}/,
+ ActiveRecord::Base.connection_config[:database])
require "#{app_path}/app/models/book"
assert_equal 2, Book.count
end
@@ -129,8 +129,8 @@ module ApplicationTests
assert_match(/CREATE TABLE \"books\"/, structure_dump)
`bundle exec rake db:drop`
`bundle exec rake db:structure:load`
- assert_match /#{expected[:database]}/,
- ActiveRecord::Base.connection_config[:database]
+ assert_match(/#{expected[:database]}/,
+ ActiveRecord::Base.connection_config[:database])
require "#{app_path}/app/models/book"
#if structure is not loaded correctly, exception would be raised
assert Book.count, 0
@@ -161,8 +161,8 @@ module ApplicationTests
require "#{app_path}/app/models/book"
#if structure is not loaded correctly, exception would be raised
assert Book.count, 0
- assert_match /#{ActiveRecord::Base.configurations['test']['database']}/,
- ActiveRecord::Base.connection_config[:database]
+ assert_match(/#{ActiveRecord::Base.configurations['test']['database']}/,
+ ActiveRecord::Base.connection_config[:database])
end
end
diff --git a/railties/test/queueing/container_test.rb b/railties/test/queueing/container_test.rb
deleted file mode 100644
index 69e59a3871..0000000000
--- a/railties/test/queueing/container_test.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require 'abstract_unit'
-require 'rails/queueing'
-
-module Rails
- module Queueing
- class ContainerTest < ActiveSupport::TestCase
- def test_delegates_to_default
- q = Queue.new
- container = Container.new q
- job = Object.new
-
- container.push job
- assert_equal job, q.pop
- end
-
- def test_access_default
- q = Queue.new
- container = Container.new q
- assert_equal q, container[:default]
- end
-
- def test_assign_queue
- container = Container.new Object.new
- q = Object.new
- container[:foo] = q
- assert_equal q, container[:foo]
- end
- end
- end
-end