Em 24-04-2012 14:31, Jeremy Evans escreveu:
On Tuesday, April 24, 2012 9:40:58 AM UTC-7, Rodrigo Rosenfeld Rosas
wrote:
Em 24-04-2012 12:27, Jeremy Evans escreveu:
On Tuesday, April 24, 2012 6:55:29 AM UTC-7, Rodrigo Rosenfeld
Rosas wrote:
Moving on, the problem is that I'd like to have a set of
records to be created for context, but only once or it would
be too slow to run the spec.
Then just add the records before the spec and delete them after:
before(:all){# Add some records here}
after(:all){# Delete the records here}
This is not that easy. For example, if you write
FactoryGirl.create(:user), this might as well create a role or
other records in the database. It is hard to keep track of every
record created behind the scenes, so it would be a nightmare to
maintain something like this.
In general, if you don't care about concurrency (i.e. you run your
specs in a single thread), it's safe to just do the following in the
after block:
[:table1, :table2, :table3, ...].each{|t| DB[t].delete}
No, I start my specs with some populated data for some tables that
shouldn't change unless in some specific examples, but I'd like them to
rollback to the original state at the end of the examples. I do really
want to use savepoints instead of a truncate strategy or I'd be already
using DatabaseCleaner for that.
Your suggested approach wouldn't work pretty well as there are some
database constraints that would require a certain order in the tables as
well. This is pretty hard to maintain anyway and it is much slower than
"truncate table1, table2, ...".
Making sure to list every table that could be modified by the related
specs. I do this in apps where the tests don't use transactions (as
they are testing an out-of-process webserver), and it's simple to
maintain.
I'd like to be able to do something like this:
context "some sample records exists" do
before(:all) do
@sample_records_transaction = DB.transaction(savepoint: true)
create_sample_records
end
after(:all) { @sample_records_transaction.rollback! } # or
even raise Rollback
# examples here
end
Could you please add support for using transactions this way?
No. Because of how the connection pool works, you need to use
blocks for transactions.
Sorry, could you please elaborate on this? What do you mean?
You need to understand how Sequel's connection pool works.
I was just looking at the code.
Unlike some other database libraries, it doesn't leak connections and
require manual cleanup later, it uses a block-based connection
checkin/checkout.
Yes, I noticed that.
By design, there is no method that allows you to checkout a connection
without forcing a checkin later. With transactions, you need to
ensure that all database queries use the same connection (the one that
started the transaction).
Yes, I've realized that too. This makes it really hard to me to manually
create the savepoints by myself while still using Sequel transaction
support in the around(:each) block.
The way to do that is checking out a connection at the start of the
transaction block, and checking in the connection at the end of the
transaction block. You cannot just checkout a connection to issue the
BEGIN and then check the connection back in, as the connection code
theoretically be used by other threads that should not be operating
inside the transaction.
Sorry this is where I got confused. Could you please give me a concrete
example?
You are free to implement such things yourself if you want. In
single threaded mode, you could probably get something that works OK.
Sorry, but I couldn't understand what is the thread-safety role here.
I'm sure if you read the connection pool and transaction related code,
you probably would. You could then probably also figure out how to
implement what you want yourself.
I've read the code and I understand why it is difficult to allow the
usage I proposed in my previous message. But I couldn't figure it out
how to implement what I want by myself.
To hopefully be more clear: what you want is not implemented because
it is a bad idea, not because it is difficult to implement.
Then please point me to some example on how I could do that manually as
I'm having troubles on understanding how to do that by myself.
For example, I'd need to issue the BEGIN in the before(:all) to finally
issue the ROLLBACK TO SAVEPOINT in the after(:all).
But I need a connection from the pool for being able to do that, and I
can't get one because I have to use it inside a block.
Also when the before(:each) is called, Sequel.transaction wouldn't know
what is the current depth level.
So, as you can see, I'm totally lost on how to approach that.
If I was going to run my specs concurrently, I'd make sure that a
different connection would be used for each "describe" block and I
wouldn't run multiple examples of the same outer-most block concurrently.
Could you please give me some hint on how to achieve that with Sequel?
Thanks in advance,
Rodrigo.
--
You received this message because you are subscribed to the Google Groups
"sequel-talk" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/sequel-talk?hl=en.