diff options
author | Jeremy Kemper <jeremy@bitsweat.net> | 2005-09-30 03:39:15 +0000 |
---|---|---|
committer | Jeremy Kemper <jeremy@bitsweat.net> | 2005-09-30 03:39:15 +0000 |
commit | e8286579738840c3df33dbafe86902d96f0b20f5 (patch) | |
tree | d185d127bd87a44dc1c5f198ff243f8907875244 /activerecord/test/transactions_test.rb | |
parent | 4ce9b4c5575cad6f5f1ccd69ddb57d06640e2422 (diff) | |
download | rails-e8286579738840c3df33dbafe86902d96f0b20f5.tar.gz rails-e8286579738840c3df33dbafe86902d96f0b20f5.tar.bz2 rails-e8286579738840c3df33dbafe86902d96f0b20f5.zip |
Move transaction thread-safety test to transactions_test. Check that simultaneous transactions don't step on each others' toes. Check that simultaneous transactions don't give dirty reads (read-committed txn isolation or greater.)
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@2417 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'activerecord/test/transactions_test.rb')
-rw-r--r-- | activerecord/test/transactions_test.rb | 90 |
1 files changed, 79 insertions, 11 deletions
diff --git a/activerecord/test/transactions_test.rb b/activerecord/test/transactions_test.rb index 806ea0e207..0048e24bc7 100644 --- a/activerecord/test/transactions_test.rb +++ b/activerecord/test/transactions_test.rb @@ -1,11 +1,11 @@ require 'abstract_unit' require 'fixtures/topic' - +require 'fixtures/developer' class TransactionTest < Test::Unit::TestCase self.use_transactional_fixtures = false - fixtures :topics + fixtures :topics, :developers def setup # sqlite does not seem to return these in the right order, so we sort them @@ -15,8 +15,8 @@ class TransactionTest < Test::Unit::TestCase def test_successful Topic.transaction do - @first.approved = 1 - @second.approved = 0 + @first.approved = true + @second.approved = false @first.save @second.save end @@ -27,8 +27,8 @@ class TransactionTest < Test::Unit::TestCase def transaction_with_return Topic.transaction do - @first.approved = 1 - @second.approved = 0 + @first.approved = true + @second.approved = false @first.save @second.save return @@ -58,8 +58,8 @@ class TransactionTest < Test::Unit::TestCase def test_successful_with_instance_method @first.transaction do - @first.approved = 1 - @second.approved = 0 + @first.approved = true + @second.approved = false @first.save @second.save end @@ -125,8 +125,8 @@ class TransactionTest < Test::Unit::TestCase def test_nested_explicit_transactions Topic.transaction do Topic.transaction do - @first.approved = 1 - @second.approved = 0 + @first.approved = true + @second.approved = false @first.save @second.save end @@ -135,7 +135,75 @@ class TransactionTest < Test::Unit::TestCase assert Topic.find(1).approved?, "First should have been approved" assert !Topic.find(2).approved?, "Second should have been unapproved" end - + + # This will cause transactions to overlap and fail unless they are + # performed on separate database connections. + def test_transaction_per_thread + assert_nothing_raised do + threads = (1..20).map do + Thread.new do + Topic.transaction do + topic = Topic.find(:first) + topic.approved = !topic.approved? + topic.save! + topic.approved = !topic.approved? + topic.save! + end + end + end + + threads.each { |t| t.join } + end + end + + # Test for dirty reads among simultaneous transactions. + def test_transaction_isolation__read_committed + # Should be invariant. + original_salary = Developer.find(1).salary + temporary_salary = 200000 + + assert_nothing_raised do + threads = (1..20).map do + Thread.new do + Developer.transaction do + # Expect original salary. + dev = Developer.find(1) + assert_equal original_salary, dev.salary + + dev.salary = temporary_salary + dev.save! + + # Expect temporary salary. + dev = Developer.find(1) + assert_equal temporary_salary, dev.salary + + dev.salary = original_salary + dev.save! + + # Expect original salary. + dev = Developer.find(1) + assert_equal original_salary, dev.salary + end + end + end + + # Keep our eyes peeled. + threads << Thread.new do + 10.times do + sleep 0.05 + Developer.transaction do + # Always expect original salary. + assert_equal original_salary, Developer.find(1).salary + end + end + end + + threads.each { |t| t.join } + end + + assert_equal original_salary, Developer.find(1).salary + end + private def add_exception_raising_after_save_callback_to_topic |