11require 'spec_helper'
22
33# We don't need to run the expensive parallel tests for every combination of prefix/suffix.
4- # Those affect SQL generation, not parallelism
4+ # Those affect SQL generation, not parallelism.
5+ # SQLite doesn't support concurrency reliably, either.
56def run_parallel_tests?
6- ActiveRecord ::Base . table_name_prefix . empty? &&
7+ !sqlite? &&
8+ ActiveRecord ::Base . table_name_prefix . empty? &&
79 ActiveRecord ::Base . table_name_suffix . empty?
810end
911
1012def max_threads
1113 5
1214end
1315
14-
1516class WorkerBase
1617 extend Forwardable
1718 attr_reader :name
@@ -106,7 +107,7 @@ def run_workers(worker_class = FindOrCreateWorker)
106107 run_workers
107108 # duplication from at least one iteration:
108109 expect ( Tag . where ( name : @names ) . size ) . to be > @iterations
109- end unless sqlite? # sqlite throws errors from concurrent access
110+ end
110111
111112 class SiblingPrependerWorker < WorkerBase
112113 def before_work
@@ -119,50 +120,6 @@ def work
119120 end
120121 end
121122
122- # TODO: this test should be rewritten to be proper producer-consumer code
123- xit 'fails to deadlock from parallel sibling churn' do
124- # target should be non-trivially long to maximize time spent in hierarchy maintenance
125- target = Tag . find_or_create_by_path ( ( 'a' ..'z' ) . to_a + ( 'A' ..'Z' ) . to_a )
126- expected_children = ( 1 ..100 ) . to_a . map { |ea | "root ##{ ea } " }
127- children_to_add = expected_children . dup
128- added_children = [ ]
129- children_to_delete = [ ]
130- deleted_children = [ ]
131- creator_threads = @workers . times . map do
132- Thread . new do
133- while children_to_add . present?
134- name = children_to_add . shift
135- unless name . nil?
136- Tag . transaction { target . find_or_create_by_path ( name ) }
137- children_to_delete << name
138- added_children << name
139- end
140- end
141- end
142- end
143- run_destruction = true
144- destroyer_threads = @workers . times . map do
145- Thread . new do
146- begin
147- victim_name = children_to_delete . shift
148- if victim_name
149- Tag . transaction do
150- victim = target . children . where ( name : victim_name ) . first
151- victim . destroy
152- deleted_children << victim_name
153- end
154- else
155- sleep rand # wait for more victims
156- end
157- end while run_destruction || !children_to_delete . empty?
158- end
159- end
160- creator_threads . each ( &:join )
161- destroyer_threads . each ( &:join )
162- expect ( added_children ) . to match ( expected_children )
163- expect ( deleted_children ) . to match ( expected_children )
164- end
165-
166123 it 'fails to deadlock while simultaneously deleting items from the same hierarchy' do
167124 target = User . find_or_create_by_path ( ( 1 ..200 ) . to_a . map { |ea | ea . to_s } )
168125 emails = target . self_and_ancestors . to_a . map ( &:email ) . shuffle
@@ -176,7 +133,7 @@ def work
176133 end
177134 User . connection . reconnect!
178135 expect ( User . all ) . to be_empty
179- end unless sqlite? # sqlite throws errors from concurrent access
136+ end
180137
181138 class SiblingPrependerWorker < WorkerBase
182139 def before_work
@@ -198,6 +155,5 @@ def work
198155
199156 # The only non-root node should be "root":
200157 expect ( Label . all . select { |ea | ea . root? } ) . to eq ( [ @target . parent ] )
201- end unless sqlite? # sqlite throws errors from concurrent access
202-
158+ end
203159end if run_parallel_tests?
0 commit comments