test_after_commit 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Appraisals CHANGED
@@ -10,3 +10,7 @@ appraise "32" do
10
10
  gem "activerecord", "~> 3.2.6"
11
11
  end
12
12
 
13
+ appraise "40" do
14
+ gem "activerecord", "~> 4.0.0.beta1"
15
+ gem "rails-observers"
16
+ end
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source :rubygems
1
+ source "https://rubygems.org"
2
2
  gemspec
3
3
 
4
4
  gem 'rake'
data/Gemfile.lock CHANGED
@@ -1,10 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- test_after_commit (0.0.1)
4
+ test_after_commit (0.1.0)
5
5
 
6
6
  GEM
7
- remote: http://rubygems.org/
7
+ remote: https://rubygems.org/
8
8
  specs:
9
9
  activemodel (3.0.15)
10
10
  activesupport (= 3.0.15)
data/Rakefile CHANGED
@@ -6,7 +6,7 @@ task :spec do
6
6
  end
7
7
 
8
8
  task :default do
9
- sh "bundle exec rake appraisal:install && bundle exec rake appraisal spec"
9
+ sh "bundle exec rake appraisal:install && bundle exec rake appraisal spec && REAL=1 bundle exec rake appraisal spec"
10
10
  end
11
11
 
12
12
  # extracted from https://github.com/grosser/project_template
data/Readme.md CHANGED
@@ -8,12 +8,19 @@ Install
8
8
  # Gemfile
9
9
  gem 'test_after_commit', :group => :test
10
10
 
11
+ TIPS
12
+ ====
13
+ - hooks do not re-raise errors (with or without this gem)
14
+
11
15
  Author
12
16
  ======
13
17
 
14
18
  Inspired by https://gist.github.com/1305285
15
19
 
20
+ ### [Contributors](https://github.com/grosser/test_after_commit/contributors)
21
+ - [James Le Cuirot](https://github.com/chewi)
22
+
16
23
  [Michael Grosser](http://grosser.it)<br/>
17
24
  michael@grosser.it<br/>
18
25
  License: MIT<br/>
19
- [![Build Status](https://secure.travis-ci.org/grosser/test_after_commit.png)](http://travis-ci.org/grosser/test_after_commit)
26
+ [![Build Status](https://travis-ci.org/grosser/test_after_commit.png)](https://travis-ci.org/grosser/test_after_commit)
data/gemfiles/30.gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  # This file was generated by Appraisal
2
2
 
3
- source :rubygems
3
+ source "https://rubygems.org"
4
4
 
5
5
  gem "rake"
6
6
  gem "rspec", "~>2"
@@ -1,10 +1,10 @@
1
1
  PATH
2
2
  remote: /Users/mgrosser/code/tools/test_after_commit
3
3
  specs:
4
- test_after_commit (0.0.0)
4
+ test_after_commit (0.0.1)
5
5
 
6
6
  GEM
7
- remote: http://rubygems.org/
7
+ remote: https://rubygems.org/
8
8
  specs:
9
9
  activemodel (3.0.16)
10
10
  activesupport (= 3.0.16)
data/gemfiles/31.gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  # This file was generated by Appraisal
2
2
 
3
- source :rubygems
3
+ source "https://rubygems.org"
4
4
 
5
5
  gem "rake"
6
6
  gem "rspec", "~>2"
@@ -1,10 +1,10 @@
1
1
  PATH
2
2
  remote: /Users/mgrosser/code/tools/test_after_commit
3
3
  specs:
4
- test_after_commit (0.0.0)
4
+ test_after_commit (0.0.1)
5
5
 
6
6
  GEM
7
- remote: http://rubygems.org/
7
+ remote: https://rubygems.org/
8
8
  specs:
9
9
  activemodel (3.1.7)
10
10
  activesupport (= 3.1.7)
data/gemfiles/32.gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  # This file was generated by Appraisal
2
2
 
3
- source :rubygems
3
+ source "https://rubygems.org"
4
4
 
5
5
  gem "rake"
6
6
  gem "rspec", "~>2"
@@ -1,10 +1,10 @@
1
1
  PATH
2
2
  remote: /Users/mgrosser/code/tools/test_after_commit
3
3
  specs:
4
- test_after_commit (0.0.0)
4
+ test_after_commit (0.0.1)
5
5
 
6
6
  GEM
7
- remote: http://rubygems.org/
7
+ remote: https://rubygems.org/
8
8
  specs:
9
9
  activemodel (3.2.7)
10
10
  activesupport (= 3.2.7)
@@ -0,0 +1,12 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rake"
6
+ gem "rspec", "~>2"
7
+ gem "sqlite3"
8
+ gem "appraisal"
9
+ gem "activerecord", "~> 4.0.0.beta1"
10
+ gem "rails-observers"
11
+
12
+ gemspec :path=>"../"
@@ -0,0 +1,80 @@
1
+ PATH
2
+ remote: /Users/mgrosser/code/tools/test_after_commit
3
+ specs:
4
+ test_after_commit (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ actionpack (4.0.0.beta1)
10
+ activesupport (= 4.0.0.beta1)
11
+ builder (~> 3.1.0)
12
+ erubis (~> 2.7.0)
13
+ rack (~> 1.5.2)
14
+ rack-test (~> 0.6.2)
15
+ activemodel (4.0.0.beta1)
16
+ activesupport (= 4.0.0.beta1)
17
+ builder (~> 3.1.0)
18
+ activerecord (4.0.0.beta1)
19
+ activemodel (= 4.0.0.beta1)
20
+ activerecord-deprecated_finders (~> 0.0.3)
21
+ activesupport (= 4.0.0.beta1)
22
+ arel (~> 4.0.0.beta1)
23
+ activerecord-deprecated_finders (0.0.3)
24
+ activesupport (4.0.0.beta1)
25
+ i18n (~> 0.6.2)
26
+ minitest (~> 4.2)
27
+ multi_json (~> 1.3)
28
+ thread_safe (~> 0.1)
29
+ tzinfo (~> 0.3.33)
30
+ appraisal (0.5.1)
31
+ bundler
32
+ rake
33
+ arel (4.0.0.beta2)
34
+ atomic (1.0.1)
35
+ builder (3.1.4)
36
+ diff-lcs (1.2.1)
37
+ erubis (2.7.0)
38
+ i18n (0.6.4)
39
+ json (1.7.7)
40
+ minitest (4.6.2)
41
+ multi_json (1.6.1)
42
+ rack (1.5.2)
43
+ rack-test (0.6.2)
44
+ rack (>= 1.0)
45
+ rails-observers (0.1.1)
46
+ railties (~> 4.0.0.beta)
47
+ railties (4.0.0.beta1)
48
+ actionpack (= 4.0.0.beta1)
49
+ activesupport (= 4.0.0.beta1)
50
+ rake (>= 0.8.7)
51
+ rdoc (~> 3.4)
52
+ thor (>= 0.17.0, < 2.0)
53
+ rake (10.0.3)
54
+ rdoc (3.12.2)
55
+ json (~> 1.4)
56
+ rspec (2.13.0)
57
+ rspec-core (~> 2.13.0)
58
+ rspec-expectations (~> 2.13.0)
59
+ rspec-mocks (~> 2.13.0)
60
+ rspec-core (2.13.1)
61
+ rspec-expectations (2.13.0)
62
+ diff-lcs (>= 1.1.3, < 2.0)
63
+ rspec-mocks (2.13.0)
64
+ sqlite3 (1.3.7)
65
+ thor (0.17.0)
66
+ thread_safe (0.1.0)
67
+ atomic
68
+ tzinfo (0.3.37)
69
+
70
+ PLATFORMS
71
+ ruby
72
+
73
+ DEPENDENCIES
74
+ activerecord (~> 4.0.0.beta1)
75
+ appraisal
76
+ rails-observers
77
+ rake
78
+ rspec (~> 2)
79
+ sqlite3
80
+ test_after_commit!
@@ -3,63 +3,64 @@ require 'test_after_commit/version'
3
3
  module TestAfterCommit
4
4
  end
5
5
 
6
- # https://gist.github.com/1305285 + removed RSpec specific code
6
+ $PASS = 0
7
+
7
8
  ActiveRecord::ConnectionAdapters::DatabaseStatements.class_eval do
8
- #
9
- # Run the normal transaction method; when it's done, check to see if there
10
- # is exactly one open transaction. If so, that's the transactional
11
- # fixtures transaction; from the model's standpoint, the completed
12
- # transaction is the real deal. Send commit callbacks to models.
13
- #
14
- # If the transaction block raises a Rollback, we need to know, so we don't
15
- # call the commit hooks. Other exceptions don't need to be explicitly
16
- # accounted for since they will raise uncaught through this method and
17
- # prevent the code after the hook from running.
18
- #
19
9
  def transaction_with_transactional_fixtures(*args)
20
- return_value = nil
21
- rolled_back = false
22
-
10
+ @test_open_transactions ||= 0
23
11
  transaction_without_transactional_fixtures(*args) do
24
12
  begin
25
- return_value = yield
26
- rescue ActiveRecord::Rollback
27
- rolled_back = true
28
- raise
13
+ @test_open_transactions += 1
14
+ yield
15
+ rescue ActiveRecord::Rollback => e
16
+ raise e
17
+ else
18
+ if @test_open_transactions == 2
19
+ test_commit_records
20
+ end
21
+ ensure
22
+ @test_open_transactions -= 1
29
23
  end
30
24
  end
31
-
32
- commit_transaction_records(false) if not rolled_back and open_transactions == 1
33
-
34
- return_value
35
25
  end
36
26
  alias_method_chain :transaction, :transactional_fixtures
37
27
 
38
- #
39
- # The @_current_transaction_records is a stack of arrays, each one
40
- # containing the records associated with the corresponding transaction
41
- # in the transaction stack. This is used by the
42
- # `rollback_transaction_records` method (to only send a rollback hook to
43
- # models attached to the transaction being rolled back) but is usually
44
- # ignored by the `commit_transaction_records` method. Here we
45
- # monkey-patch it to temporarily replace the array with only the records
46
- # for the top-of-stack transaction, so the real
47
- # `commit_transaction_records` method only sends callbacks to those.
48
- #
49
- def commit_transaction_records_with_transactional_fixtures(commit = true)
50
- return commit_transaction_records_without_transactional_fixtures if commit
51
-
52
- preserving_current_transaction_records do
53
- @_current_transaction_records = @_current_transaction_records.pop || []
54
- commit_transaction_records_without_transactional_fixtures
28
+ def test_commit_records
29
+ if ActiveRecord::VERSION::MAJOR == 3
30
+ commit_transaction_records(false)
31
+ else
32
+ @transaction.commit_records
33
+ @transaction.records.clear # prevent duplicate .commit!
34
+ @transaction.instance_variable_get(:@state).set_state(nil)
55
35
  end
56
36
  end
57
- alias_method_chain :commit_transaction_records, :transactional_fixtures
58
37
 
59
- def preserving_current_transaction_records
60
- old_current_transaction_records = @_current_transaction_records.dup
61
- yield
62
- ensure
63
- @_current_transaction_records = old_current_transaction_records
38
+ if ActiveRecord::VERSION::MAJOR == 3
39
+ # The @_current_transaction_records is a stack of arrays, each one
40
+ # containing the records associated with the corresponding transaction
41
+ # in the transaction stack. This is used by the
42
+ # `rollback_transaction_records` method (to only send a rollback hook to
43
+ # models attached to the transaction being rolled back) but is usually
44
+ # ignored by the `commit_transaction_records` method. Here we
45
+ # monkey-patch it to temporarily replace the array with only the records
46
+ # for the top-of-stack transaction, so the real
47
+ # `commit_transaction_records` method only sends callbacks to those.
48
+ #
49
+ def commit_transaction_records_with_transactional_fixtures(commit = true)
50
+ return commit_transaction_records_without_transactional_fixtures if commit
51
+
52
+ preserving_current_transaction_records do
53
+ @_current_transaction_records = @_current_transaction_records.pop || []
54
+ commit_transaction_records_without_transactional_fixtures
55
+ end
56
+ end
57
+ alias_method_chain :commit_transaction_records, :transactional_fixtures
58
+
59
+ def preserving_current_transaction_records
60
+ old_current_transaction_records = @_current_transaction_records.dup
61
+ yield
62
+ ensure
63
+ @_current_transaction_records = old_current_transaction_records
64
+ end
64
65
  end
65
66
  end
@@ -1,3 +1,3 @@
1
1
  module TestAfterCommit
2
- VERSION = '0.0.1'
2
+ VERSION = '0.1.0'
3
3
  end
data/spec/database.rb CHANGED
@@ -1,6 +1,10 @@
1
1
  # setup database
2
2
  require 'active_record'
3
3
 
4
+ if ActiveRecord::VERSION::MAJOR > 3
5
+ require "rails/observers/activerecord/active_record"
6
+ end
7
+
4
8
  ActiveRecord::Base.establish_connection(
5
9
  :adapter => 'sqlite3',
6
10
  :database => ':memory:'
@@ -10,17 +14,21 @@ ActiveRecord::Migration.verbose = false
10
14
 
11
15
  ActiveRecord::Schema.define(:version => 1) do
12
16
  create_table "cars", :force => true do |t|
17
+ t.integer :counter, :default => 0, :null => false
18
+ t.timestamps
13
19
  end
14
20
  end
15
21
 
16
22
  class Car < ActiveRecord::Base
17
23
  after_commit :simple_after_commit
18
24
  after_commit :simple_after_commit_on_create, :on => :create
25
+ after_commit :save_once, :on => :create, :if => :do_after_create_save
19
26
  after_commit :simple_after_commit_on_update, :on => :update
27
+ after_commit :maybe_raise_errors
20
28
 
21
29
  after_save :trigger_rollback
22
30
 
23
- attr_accessor :make_rollback
31
+ attr_accessor :make_rollback, :raise_error, :do_after_create_save
24
32
 
25
33
  def self.called(x=nil)
26
34
  @called ||= []
@@ -37,6 +45,18 @@ class Car < ActiveRecord::Base
37
45
 
38
46
  private
39
47
 
48
+ def save_once
49
+ update_attributes(:counter => 3) unless counter == 3
50
+ self.class.called :save_once
51
+ end
52
+
53
+ def maybe_raise_errors
54
+ if raise_error
55
+ # puts "MAYBE RAISE" # just debugging, but it really does not work ...
56
+ raise "Expected error"
57
+ end
58
+ end
59
+
40
60
  def simple_after_commit
41
61
  self.class.called :always
42
62
  end
@@ -49,3 +69,17 @@ class Car < ActiveRecord::Base
49
69
  self.class.called :update
50
70
  end
51
71
  end
72
+
73
+ class CarObserver < ActiveRecord::Observer
74
+ cattr_accessor :recording
75
+
76
+ [:after_commit, :after_rollback].each do |action|
77
+ define_method action do |record|
78
+ return unless recording
79
+ Car.called << :observed_after_commit
80
+ end
81
+ end
82
+ end
83
+
84
+ Car.observers = :car_observer
85
+ Car.instantiate_observers
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,18 @@
1
1
  $LOAD_PATH.unshift 'lib'
2
2
  require File.expand_path '../database', __FILE__
3
- require 'test_after_commit'
3
+
4
+ if ENV['REAL']
5
+ puts 'using real transactions'
6
+ else
7
+ require 'test_after_commit'
8
+ end
9
+
10
+ RSpec.configure do |config|
11
+ unless ENV['REAL']
12
+ config.around do |example|
13
+ ActiveRecord::Base.transaction do # simulate transactional fixtures
14
+ example.call
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,11 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe TestAfterCommit do
4
- around do |example|
5
- Car.transaction do # simulate transactional fixtures
6
- Car.called.clear
7
- example.call
8
- end
4
+ before do
5
+ CarObserver.recording = false
6
+ Car.called.clear
9
7
  end
10
8
 
11
9
  it "has a VERSION" do
@@ -30,4 +28,52 @@ describe TestAfterCommit do
30
28
  car.save.should == nil
31
29
  Car.called.should == []
32
30
  end
31
+
32
+ it "does not fire multiple times in nested transactions" do
33
+ Car.transaction do
34
+ Car.transaction do
35
+ Car.create!
36
+ Car.called.should == []
37
+ end
38
+ Car.called.should == []
39
+ end
40
+ Car.called.should == [:create, :always]
41
+ end
42
+
43
+ it "does not raises errors" do
44
+ car = Car.new
45
+ car.raise_error = true
46
+ car.save!
47
+ end
48
+
49
+ it "can do 1 save in after_commit" do
50
+ if !ENV['REAL']
51
+ pending "this results in infinite loop in REAL mode except on 4.0 but works in tests except for rails 3.0"
52
+ end
53
+
54
+ car = Car.new
55
+ car.do_after_create_save = true
56
+ car.save!
57
+
58
+ expected = if ActiveRecord::VERSION::MAJOR >= 4
59
+ [:update, :always, :save_once, :always] # some kind of loop prevention ... investigate we must
60
+ else
61
+ [:save_once, :create, :always, :save_once, :create, :always]
62
+ end
63
+ Car.called.should == expected
64
+ car.counter.should == 3
65
+ end
66
+
67
+ context "Observer" do
68
+ before do
69
+ CarObserver.recording = true
70
+ end
71
+
72
+ it "should record commits" do
73
+ Car.transaction do
74
+ Car.create
75
+ end
76
+ Car.called.should == [:observed_after_commit, :create, :always]
77
+ end
78
+ end
33
79
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: test_after_commit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-03 00:00:00.000000000 Z
12
+ date: 2013-03-16 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description:
15
15
  email: michael@grosser.it
@@ -29,6 +29,8 @@ files:
29
29
  - gemfiles/31.gemfile.lock
30
30
  - gemfiles/32.gemfile
31
31
  - gemfiles/32.gemfile.lock
32
+ - gemfiles/40.gemfile
33
+ - gemfiles/40.gemfile.lock
32
34
  - lib/test_after_commit.rb
33
35
  - lib/test_after_commit/version.rb
34
36
  - spec/database.rb
@@ -50,7 +52,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
50
52
  version: '0'
51
53
  segments:
52
54
  - 0
53
- hash: -3378510041846892238
55
+ hash: -3018637931883165367
54
56
  required_rubygems_version: !ruby/object:Gem::Requirement
55
57
  none: false
56
58
  requirements:
@@ -59,10 +61,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
59
61
  version: '0'
60
62
  segments:
61
63
  - 0
62
- hash: -3378510041846892238
64
+ hash: -3018637931883165367
63
65
  requirements: []
64
66
  rubyforge_project:
65
- rubygems_version: 1.8.24
67
+ rubygems_version: 1.8.25
66
68
  signing_key:
67
69
  specification_version: 3
68
70
  summary: makes after_commit callbacks testable in Rails 3+ with transactional_fixtures