Skip to content

minitest migration 5 #413

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 0 additions & 174 deletions spec/closure_tree/user_spec.rb

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
require 'spec_helper'
# frozen_string_literal: true

require "test_helper"

# We don't need to run the expensive parallel tests for every combination of prefix/suffix.
# Those affect SQL generation, not parallelism.
Expand All @@ -16,22 +18,23 @@ def max_threads
class WorkerBase
extend Forwardable
attr_reader :name

def_delegators :@thread, :join, :wakeup, :status, :to_s

def log(msg)
puts("#{Thread.current}: #{msg}") if ENV['VERBOSE']
puts("#{Thread.current}: #{msg}") if ENV["VERBOSE"]
end

def initialize(target, name)
@target = target
@name = name
@thread = Thread.new do
ActiveRecord::Base.connection_pool.with_connection { before_work } if respond_to? :before_work
log 'going to sleep...'
log "going to sleep..."
sleep
log 'woke up...'
log "woke up..."
ActiveRecord::Base.connection_pool.with_connection { work }
log 'done.'
log "done."
end
end
end
Expand All @@ -45,14 +48,25 @@ def work
end
end

RSpec.describe 'Concurrent creation' do
before :each do
class SiblingPrependerWorker < WorkerBase
def before_work
@target.reload
@sibling = Label.new(name: SecureRandom.hex(10))
end

def work
@target.prepend_sibling @sibling
end
end

describe "Concurrent creation" do
before do
@target = nil
@iterations = 5
end

def log(msg)
puts(msg) if ENV['VERBOSE']
puts(msg) if ENV["VERBOSE"]
end

def run_workers(worker_class = FindOrCreateWorker)
Expand All @@ -61,7 +75,7 @@ def run_workers(worker_class = FindOrCreateWorker)
workers = max_threads.times.map { worker_class.new(@target, name) }
# Wait for all the threads to get ready:
while true
unready_workers = workers.select { |ea| ea.status != 'sleep' }
unready_workers = workers.select { |ea| ea.status != "sleep" }
if unready_workers.empty?
break
else
Expand All @@ -71,59 +85,57 @@ def run_workers(worker_class = FindOrCreateWorker)
end
sleep(0.25)
# OK, GO!
log 'Calling .wakeup on all workers...'
log "Calling .wakeup on all workers..."
workers.each(&:wakeup)
sleep(0.25)
# Then wait for them to finish:
log 'Calling .join on all workers...'
log "Calling .join on all workers..."
workers.each(&:join)
end
# Ensure we're still connected:
ActiveRecord::Base.connection_pool.connection
end

it 'will not create dupes from class methods' do
it "will not create dupes from class methods" do
skip("unsupported") unless run_parallel_tests?

run_workers
expect(Tag.roots.collect { |ea| ea.name }).to match_array(@names)
assert_equal @names.sort, Tag.roots.collect { |ea| ea.name }.sort
# No dupe children:
%w(a b c).each do |ea|
expect(Tag.where(name: ea).size).to eq(@iterations)
%w[a b c].each do |ea|
assert_equal @iterations, Tag.where(name: ea).size
end
end

it 'will not create dupes from instance methods' do
@target = Tag.create!(name: 'root')
run_workers
expect(@target.reload.children.collect { |ea| ea.name }).to match_array(@names)
expect(Tag.where(name: @names).size).to eq(@iterations)
%w(a b c).each do |ea|
expect(Tag.where(name: ea).size).to eq(@iterations)
end
end
it "will not create dupes from instance methods" do
skip("unsupported") unless run_parallel_tests?

it 'creates dupe roots without advisory locks' do
# disable with_advisory_lock:
allow(Tag).to receive(:with_advisory_lock) { |_lock_name, &block| block.call }
@target = Tag.create!(name: "root")
run_workers
# duplication from at least one iteration:
expect(Tag.where(name: @names).size).to be > @iterations
assert_equal @names.sort, @target.reload.children.collect { |ea| ea.name }.sort
assert_equal @iterations, Tag.where(name: @names).size
%w[a b c].each do |ea|
assert_equal @iterations, Tag.where(name: ea).size
end
end

class SiblingPrependerWorker < WorkerBase
def before_work
@target.reload
@sibling = Label.new(name: SecureRandom.hex(10))
end
it "creates dupe roots without advisory locks" do
skip("unsupported") unless run_parallel_tests?

def work
@target.prepend_sibling @sibling
# disable with_advisory_lock:
Tag.stub(:with_advisory_lock, ->(_lock_name, &block) { block.call }) do
run_workers
# duplication from at least one iteration:
assert Tag.where(name: @names).size > @iterations
end
end

it 'fails to deadlock while simultaneously deleting items from the same hierarchy' do
it "fails to deadlock while simultaneously deleting items from the same hierarchy" do
skip("unsupported") unless run_parallel_tests?

target = User.find_or_create_by_path((1..200).to_a.map { |ea| ea.to_s })
emails = target.self_and_ancestors.to_a.map(&:email).shuffle
Parallel.map(emails, :in_threads => max_threads) do |email|
Parallel.map(emails, in_threads: max_threads) do |email|
ActiveRecord::Base.connection_pool.with_connection do
User.transaction do
log "Destroying #{email}..."
Expand All @@ -132,28 +144,19 @@ def work
end
end
User.connection.reconnect!
expect(User.all).to be_empty
assert User.all.empty?
end

class SiblingPrependerWorker < WorkerBase
def before_work
@target.reload
@sibling = Label.new(name: SecureRandom.hex(10))
end
it "fails to deadlock from prepending siblings" do
skip("unsupported") unless run_parallel_tests?

def work
@target.prepend_sibling @sibling
end
end

it 'fails to deadlock from prepending siblings' do
@target = Label.find_or_create_by_path %w(root parent)
@target = Label.find_or_create_by_path %w[root parent]
run_workers(SiblingPrependerWorker)
children = Label.roots
uniq_order_values = children.collect { |ea| ea.order_value }.uniq
expect(children.size).to eq(uniq_order_values.size)
assert_equal uniq_order_values.size, children.size

# The only non-root node should be "root":
expect(Label.all.select { |ea| ea.root? }).to eq([@target.parent])
assert_equal([@target.parent], Label.all.select { |ea| ea.root? })
end
end if run_parallel_tests?
end
Loading