Following this blog post, http://blog.arkency.com/2015/09/testing-race-conditions/
I am trying to test concurrency. But in my specs, I am not able to find the record when I spin up a new thread or fork a process.
describe 'test concurrency' do
let(:order_1) { create(:order) }
let(:order_2) { create(:order) }
let(:order_3) { create(:order) }
let(:order_4) { create(:order) }
let(:product) { create(:product) }
it 'test concurrency' do
wait_for_all_threads = true
product.update(quantity_available: 4, quantity_sold: 0, quantity_in_carts: 0)
orders = [order_1, order_2, order_3, order_4]
# Objects are persisted in here
# because order_n.persisted => true
# product.persisted => true
# product.reload works without issue (and this is essentially what causes the RecordNotFound error in Order#add_item)
threads = orders.map do |order|
Thread.new do
# Objects cannot be found in the database
true while wait_for_all_threads
item = order.add_item(product, 1)
order_items << item
end
end
wait_for_all_threads = false
threads.each(&:join)
# ...
# here comes all the expects ...
# not gonna post it because it's not what matters in this question
end
end
After research, I've set these:
DatabaseCleaner.strategy = :truncation
config.use_transactional_fixtures = false
But no luck.
So the issue is, within the new thread, none of the created objects can be found in the database.
Some clues as I am digging:
persisted?
)after_commit
won't run in rspec)I use the database_cleaner gem to scrub my test database before each test runs, ensuring a clean slate and stable baseline every time. By default, RSpec will actually do this for you, running every test with a database transaction and then rolling back that transaction after it finishes.
Factory Bot is a helper for writing factories for Ruby tests. It was previously known as Factory Girl. For older versions, use FactoryGirl instead of FactoryBot . Factory Bot documentation (rubydoc.info) Getting started (github.com)
The describe Keyword The word describe is an RSpec keyword. It is used to define an “Example Group”. You can think of an “Example Group” as a collection of tests. The describe keyword can take a class name and/or string argument.
RSpec is a testing tool for Ruby, created for behavior-driven development (BDD). It is the most frequently used testing library for Ruby in production applications. Even though it has a very rich and powerful DSL (domain-specific language), at its core it is a simple tool which you can start using rather quickly.
Using Rails 5 this worked for me. Place within the describe:
self.use_transactional_tests = false
"use_transactional_fixtures" has been deprecated.
I also had to bypass DatabaseCleaner via the following:
it 'tests concurrency', bypass_cleaner: true do
end
Then in rails_helper (or where you have DatabaseCleaner settings)
config.around(:each) do |example|
if example.metadata[:bypass_cleaner]
example.run
else
# database cleaner code
end
end
I hope this helps you or somebody else out :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With