1- require 'spec_helper'
1+ # frozen_string_literal: true
2+
3+ require "test_helper"
24
35# We don't need to run the expensive parallel tests for every combination of prefix/suffix.
46# Those affect SQL generation, not parallelism.
@@ -16,22 +18,23 @@ def max_threads
1618class WorkerBase
1719 extend Forwardable
1820 attr_reader :name
21+
1922 def_delegators :@thread , :join , :wakeup , :status , :to_s
2023
2124 def log ( msg )
22- puts ( "#{ Thread . current } : #{ msg } " ) if ENV [ ' VERBOSE' ]
25+ puts ( "#{ Thread . current } : #{ msg } " ) if ENV [ " VERBOSE" ]
2326 end
2427
2528 def initialize ( target , name )
2629 @target = target
2730 @name = name
2831 @thread = Thread . new do
2932 ActiveRecord ::Base . connection_pool . with_connection { before_work } if respond_to? :before_work
30- log ' going to sleep...'
33+ log " going to sleep..."
3134 sleep
32- log ' woke up...'
35+ log " woke up..."
3336 ActiveRecord ::Base . connection_pool . with_connection { work }
34- log ' done.'
37+ log " done."
3538 end
3639 end
3740end
@@ -45,14 +48,25 @@ def work
4548 end
4649end
4750
48- RSpec . describe 'Concurrent creation' do
49- before :each do
51+ class SiblingPrependerWorker < WorkerBase
52+ def before_work
53+ @target . reload
54+ @sibling = Label . new ( name : SecureRandom . hex ( 10 ) )
55+ end
56+
57+ def work
58+ @target . prepend_sibling @sibling
59+ end
60+ end
61+
62+ describe "Concurrent creation" do
63+ before do
5064 @target = nil
5165 @iterations = 5
5266 end
5367
5468 def log ( msg )
55- puts ( msg ) if ENV [ ' VERBOSE' ]
69+ puts ( msg ) if ENV [ " VERBOSE" ]
5670 end
5771
5872 def run_workers ( worker_class = FindOrCreateWorker )
@@ -61,7 +75,7 @@ def run_workers(worker_class = FindOrCreateWorker)
6175 workers = max_threads . times . map { worker_class . new ( @target , name ) }
6276 # Wait for all the threads to get ready:
6377 while true
64- unready_workers = workers . select { |ea | ea . status != ' sleep' }
78+ unready_workers = workers . select { |ea | ea . status != " sleep" }
6579 if unready_workers . empty?
6680 break
6781 else
@@ -71,59 +85,57 @@ def run_workers(worker_class = FindOrCreateWorker)
7185 end
7286 sleep ( 0.25 )
7387 # OK, GO!
74- log ' Calling .wakeup on all workers...'
88+ log " Calling .wakeup on all workers..."
7589 workers . each ( &:wakeup )
7690 sleep ( 0.25 )
7791 # Then wait for them to finish:
78- log ' Calling .join on all workers...'
92+ log " Calling .join on all workers..."
7993 workers . each ( &:join )
8094 end
8195 # Ensure we're still connected:
8296 ActiveRecord ::Base . connection_pool . connection
8397 end
8498
85- it 'will not create dupes from class methods' do
99+ it "will not create dupes from class methods" do
100+ skip ( "unsupported" ) unless run_parallel_tests?
101+
86102 run_workers
87- expect ( Tag . roots . collect { |ea | ea . name } ) . to match_array ( @names )
103+ assert_equal @names . sort , Tag . roots . collect { |ea | ea . name } . sort
88104 # No dupe children:
89- %w( a b c ) . each do |ea |
90- expect ( Tag . where ( name : ea ) . size ) . to eq ( @iterations )
105+ %w[ a b c ] . each do |ea |
106+ assert_equal @iterations , Tag . where ( name : ea ) . size
91107 end
92108 end
93109
94- it 'will not create dupes from instance methods' do
95- @target = Tag . create! ( name : 'root' )
96- run_workers
97- expect ( @target . reload . children . collect { |ea | ea . name } ) . to match_array ( @names )
98- expect ( Tag . where ( name : @names ) . size ) . to eq ( @iterations )
99- %w( a b c ) . each do |ea |
100- expect ( Tag . where ( name : ea ) . size ) . to eq ( @iterations )
101- end
102- end
110+ it "will not create dupes from instance methods" do
111+ skip ( "unsupported" ) unless run_parallel_tests?
103112
104- it 'creates dupe roots without advisory locks' do
105- # disable with_advisory_lock:
106- allow ( Tag ) . to receive ( :with_advisory_lock ) { |_lock_name , &block | block . call }
113+ @target = Tag . create! ( name : "root" )
107114 run_workers
108- # duplication from at least one iteration:
109- expect ( Tag . where ( name : @names ) . size ) . to be > @iterations
115+ assert_equal @names . sort , @target . reload . children . collect { |ea | ea . name } . sort
116+ assert_equal @iterations , Tag . where ( name : @names ) . size
117+ %w[ a b c ] . each do |ea |
118+ assert_equal @iterations , Tag . where ( name : ea ) . size
119+ end
110120 end
111121
112- class SiblingPrependerWorker < WorkerBase
113- def before_work
114- @target . reload
115- @sibling = Label . new ( name : SecureRandom . hex ( 10 ) )
116- end
122+ it "creates dupe roots without advisory locks" do
123+ skip ( "unsupported" ) unless run_parallel_tests?
117124
118- def work
119- @target . prepend_sibling @sibling
125+ # disable with_advisory_lock:
126+ Tag . stub ( :with_advisory_lock , -> ( _lock_name , &block ) { block . call } ) do
127+ run_workers
128+ # duplication from at least one iteration:
129+ assert Tag . where ( name : @names ) . size > @iterations
120130 end
121131 end
122132
123- it 'fails to deadlock while simultaneously deleting items from the same hierarchy' do
133+ it "fails to deadlock while simultaneously deleting items from the same hierarchy" do
134+ skip ( "unsupported" ) unless run_parallel_tests?
135+
124136 target = User . find_or_create_by_path ( ( 1 ..200 ) . to_a . map { |ea | ea . to_s } )
125137 emails = target . self_and_ancestors . to_a . map ( &:email ) . shuffle
126- Parallel . map ( emails , : in_threads => max_threads ) do |email |
138+ Parallel . map ( emails , in_threads : max_threads ) do |email |
127139 ActiveRecord ::Base . connection_pool . with_connection do
128140 User . transaction do
129141 log "Destroying #{ email } ..."
@@ -132,28 +144,19 @@ def work
132144 end
133145 end
134146 User . connection . reconnect!
135- expect ( User . all ) . to be_empty
147+ assert User . all . empty?
136148 end
137149
138- class SiblingPrependerWorker < WorkerBase
139- def before_work
140- @target . reload
141- @sibling = Label . new ( name : SecureRandom . hex ( 10 ) )
142- end
150+ it "fails to deadlock from prepending siblings" do
151+ skip ( "unsupported" ) unless run_parallel_tests?
143152
144- def work
145- @target . prepend_sibling @sibling
146- end
147- end
148-
149- it 'fails to deadlock from prepending siblings' do
150- @target = Label . find_or_create_by_path %w( root parent )
153+ @target = Label . find_or_create_by_path %w[ root parent ]
151154 run_workers ( SiblingPrependerWorker )
152155 children = Label . roots
153156 uniq_order_values = children . collect { |ea | ea . order_value } . uniq
154- expect ( children . size ) . to eq ( uniq_order_values . size )
157+ assert_equal uniq_order_values . size , children . size
155158
156159 # The only non-root node should be "root":
157- expect ( Label . all . select { |ea | ea . root? } ) . to eq ( [ @target . parent ] )
160+ assert_equal ( [ @target . parent ] , Label . all . select { |ea | ea . root? } )
158161 end
159- end if run_parallel_tests?
162+ end
0 commit comments