Nested Describe Block - transaction handling #26

Closed
jgebal opened this Issue Mar 21, 2012 · 4 comments

Comments

Projects
None yet
2 participants
@jgebal
Contributor

jgebal commented Mar 21, 2012

Hi Ray!
I have an issue. I think it it more of an issue or RSpec.configure.
The thing is that the current transactions and savepoints handling doesn't work well with nested "describe" blocks.
I find using nested describe very useful.
Here is a test to show the issue.
Pleas let me know if there is a workaround for that.

require File.dirname(FILE) + '/../spec_helper'

begin
plsql.execute("DROP TABLE t_tmp_transaction_test")
rescue
end
plsql.execute("CREATE TABLE t_tmp_transaction_test (block_name VARCHAR2(100))")

def mark_transaction(bn)
plsql.t_tmp_transaction_test.insert(:block_name=>bn.last)
end

describe "Spec - Transaction Handling. Main Block" do

transaction_points = []

before(:all) do
mark_transaction(transaction_points << "Before All - Main block")
puts transaction_points.last
end

before(:each) do
mark_transaction(transaction_points << " Before Each - Main block")
puts transaction_points.last
end

[:first, :second].each do |block_no|
describe "Nested describe block - #{block_no.to_s}." do

  before(:all) do
    mark_transaction( transaction_points  << "  Before All - #{block_no.to_s} block" )
    puts transaction_points.last
  end

  before(:each) do
    mark_transaction( transaction_points  << "   Before Each - #{block_no.to_s} block" )
    puts transaction_points.last
  end

  [:First, :Second].each do |test_no|
    it "#{test_no.to_s} Test" do
      mark_transaction( transaction_points  << "    Running #{test_no.to_s} Unit Test - #{block_no.to_s} block" )
      puts transaction_points.last
      result = plsql.t_tmp_transaction_test.all.map{|row| row.values}.flatten
      result.should =~ transaction_points
      transaction_points.pop
    end
  end

  after(:each) do
    puts "   After Each - #{block_no.to_s} block"
    transaction_points.pop
  end

  after(:all) do
    puts "  After All - #{block_no.to_s} block"
    transaction_points.pop
  end
end

end

[:third].each do |block_no|
describe "Nested describe block - #{block_no.to_s}." do

  before(:all) do
    mark_transaction( transaction_points  << "  Before All - #{block_no.to_s} block" )
    puts transaction_points.last
  end

  before(:each) do
    mark_transaction( transaction_points  << "   Before Each - #{block_no.to_s} block" )
    puts transaction_points.last
  end

  [:First, :Second].each do |test_no|
    it "#{test_no.to_s} Test" do
      mark_transaction( transaction_points  << "    Running #{test_no.to_s} Unit Test - #{block_no.to_s} block" )
      puts transaction_points.last
      result = plsql.t_tmp_transaction_test.all.map{|row| row.values}.flatten
      result.should =~ transaction_points
      transaction_points.pop
    end
  end

  after(:each) do
    puts "   After Each - #{block_no.to_s} block"
    transaction_points.pop
  end

  after(:all) do
    puts "  After All - #{block_no.to_s} block"
    transaction_points.pop
  end

end

end

it "Test outside the nested block" do
result = plsql.t_tmp_transaction_test.all.map{|row| row.values}.flatten
result.should =~ transaction_points
end

after(:each) do
puts " After Each - Main block"
transaction_points.pop
end

after(:all) do
puts "After All - Main block"
transaction_points.pop
end

end

@rsim

This comment has been minimized.

Show comment
Hide comment
@rsim

rsim Mar 21, 2012

Owner

Are you referring to default spec_helper.rb from ruby-plsql-spec? https://github.com/rsim/ruby-plsql-spec/blob/master/lib/plsql/spec/templates/spec_helper.rb

If you have nested describes then you probably need to implement generation of unique savepoint names for nested describes. Maybe something like this could work (haven't tested it :)):

RSpec.configure do |config|
  config.before(:all) do
    # @describe_level will start from 0 and then increment for each nested describe block
    @describe_level = (@describe_leve l| - 1) + 1
    if @describe_level > 0
      database_connections.each do |name|
        plsql(name).savepoint "before_all_#{@describe_level}"
      end
    end
  end
  config.before(:each) do
    database_connections.each do |name|
      plsql(name).savepoint "before_each"
    end
  end
  config.after(:each) do
    # Always perform rollback to savepoint after each test
    database_connections.each do |name|
      plsql(name).rollback_to "before_each"
    end
  end
  config.after(:all) do
    # Always perform rollback after each describe block
    if @describe_level > 0
      database_connections.each do |name|
        plsql(name).rollback_to "before_all_#{@describe_level}"
      end
    else
      database_connections.each do |name|
        plsql(name).rollback
      end
    end
    @describe_level -= 1
  end
end
Owner

rsim commented Mar 21, 2012

Are you referring to default spec_helper.rb from ruby-plsql-spec? https://github.com/rsim/ruby-plsql-spec/blob/master/lib/plsql/spec/templates/spec_helper.rb

If you have nested describes then you probably need to implement generation of unique savepoint names for nested describes. Maybe something like this could work (haven't tested it :)):

RSpec.configure do |config|
  config.before(:all) do
    # @describe_level will start from 0 and then increment for each nested describe block
    @describe_level = (@describe_leve l| - 1) + 1
    if @describe_level > 0
      database_connections.each do |name|
        plsql(name).savepoint "before_all_#{@describe_level}"
      end
    end
  end
  config.before(:each) do
    database_connections.each do |name|
      plsql(name).savepoint "before_each"
    end
  end
  config.after(:each) do
    # Always perform rollback to savepoint after each test
    database_connections.each do |name|
      plsql(name).rollback_to "before_each"
    end
  end
  config.after(:all) do
    # Always perform rollback after each describe block
    if @describe_level > 0
      database_connections.each do |name|
        plsql(name).rollback_to "before_all_#{@describe_level}"
      end
    else
      database_connections.each do |name|
        plsql(name).rollback
      end
    end
    @describe_level -= 1
  end
end
@jgebal

This comment has been minimized.

Show comment
Hide comment
@jgebal

jgebal Mar 21, 2012

Contributor

I have tried a different, but similar approach.
Jet, as you run the test and look at the results, you'll see that the injected (from configure) BEFORE and AFTER blocks execute only once.
Replace the RSpec.configure with this block and run the test to see what i have in mind.
I think that the BEFORE and AFTER injected by configure should be executed each time the block is called in SPEC file, but it is not, therefore it is impossible to manage DB transaction in nested describe blocks.
Should i report it to the RSpec team, or is there a switch that you know of which enables the expected behavior.

describe_level=nil
RSpec.configure do |config|
  config.before(:suite) do
    puts "******************* conf - before siute"
    describe_level=0
  end

  config.before(:all) do
    puts "******************* conf - before all"
    describe_level+=1
    database_connections.each do |name|
      plsql(name).savepoint "before_all#{describe_level}"
    end
  end
  config.before(:each) do
    puts "******************* conf - before each"
    database_connections.each do |name|
      plsql(name).savepoint "before_each"
    end
  end
  config.after(:each) do
    puts "******************* conf - after each"
    database_connections.each do |name|
      plsql(name).rollback_to "before_each"
    end
  end
  config.after(:all) do
    puts "******************* conf - after all"
    database_connections.each do |name|
      plsql(name).rollback_to "before_all#{describe_level}"
    end
    describe_level-=1
  end
  config.after(:suite) do
    puts "******************* conf - after siute"
    database_connections.each do |name|
      plsql(name).rollback
    end
  end
end
Contributor

jgebal commented Mar 21, 2012

I have tried a different, but similar approach.
Jet, as you run the test and look at the results, you'll see that the injected (from configure) BEFORE and AFTER blocks execute only once.
Replace the RSpec.configure with this block and run the test to see what i have in mind.
I think that the BEFORE and AFTER injected by configure should be executed each time the block is called in SPEC file, but it is not, therefore it is impossible to manage DB transaction in nested describe blocks.
Should i report it to the RSpec team, or is there a switch that you know of which enables the expected behavior.

describe_level=nil
RSpec.configure do |config|
  config.before(:suite) do
    puts "******************* conf - before siute"
    describe_level=0
  end

  config.before(:all) do
    puts "******************* conf - before all"
    describe_level+=1
    database_connections.each do |name|
      plsql(name).savepoint "before_all#{describe_level}"
    end
  end
  config.before(:each) do
    puts "******************* conf - before each"
    database_connections.each do |name|
      plsql(name).savepoint "before_each"
    end
  end
  config.after(:each) do
    puts "******************* conf - after each"
    database_connections.each do |name|
      plsql(name).rollback_to "before_each"
    end
  end
  config.after(:all) do
    puts "******************* conf - after all"
    database_connections.each do |name|
      plsql(name).rollback_to "before_all#{describe_level}"
    end
    describe_level-=1
  end
  config.after(:suite) do
    puts "******************* conf - after siute"
    database_connections.each do |name|
      plsql(name).rollback
    end
  end
end
@rsim

This comment has been minimized.

Show comment
Hide comment
@rsim

rsim Mar 21, 2012

Owner

Yes, didn't check by myself how it is actually working :)

Now checked that config.before(:all) and config.after(:all) in RSpec.configure are executed just before and after top level describe block. Probably this is intended behavior of RSpec :)

So the problem is if you do any database changes inside before(:all) block of nested describe blocks - they will not be rolled back automatically after this nested describe block. If you do not very big database changes inside before(:all) then maybe move everything to before(:each) - it will be correctly rolled back after each test. Or write tests that do not assume empty database :) At the end all changes will be rolled back after top level describe block.

Owner

rsim commented Mar 21, 2012

Yes, didn't check by myself how it is actually working :)

Now checked that config.before(:all) and config.after(:all) in RSpec.configure are executed just before and after top level describe block. Probably this is intended behavior of RSpec :)

So the problem is if you do any database changes inside before(:all) block of nested describe blocks - they will not be rolled back automatically after this nested describe block. If you do not very big database changes inside before(:all) then maybe move everything to before(:each) - it will be correctly rolled back after each test. Or write tests that do not assume empty database :) At the end all changes will be rolled back after top level describe block.

@stale

This comment has been minimized.

Show comment
Hide comment
@stale

stale bot Jan 13, 2018

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale bot commented Jan 13, 2018

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Jan 13, 2018

@stale stale bot closed this Jan 20, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment