| 29 |
29 |
self.use_transactional_tests = false
|
| 30 |
30 |
|
| 31 |
31 |
def setup
|
| 32 |
|
skip if sqlite? || mysql?
|
|
32 |
skip if sqlite?
|
| 33 |
33 |
User.current = nil
|
| 34 |
34 |
CustomField.delete_all
|
| 35 |
35 |
end
|
| ... | ... | |
| 74 |
74 |
assert_equal (2..61).to_a, children_bounds
|
| 75 |
75 |
end
|
| 76 |
76 |
|
|
77 |
def test_concurrent_subtask_removal
|
|
78 |
with_settings :notified_events => [] do
|
|
79 |
root = Issue.generate!
|
|
80 |
|
|
81 |
60.times do
|
|
82 |
Issue.generate! :parent_issue_id => root.id
|
|
83 |
end
|
|
84 |
|
|
85 |
# pick 40 random subtask ids
|
|
86 |
child_ids = Issue.where(root_id: root.id, parent_id: root.id).pluck(:id)
|
|
87 |
ids_to_remove = child_ids.sample(40).shuffle
|
|
88 |
ids_to_keep = child_ids - ids_to_remove
|
|
89 |
|
|
90 |
# remove these from the set, using four parallel threads
|
|
91 |
threads = []
|
|
92 |
ids_to_remove.each_slice(10) do |ids|
|
|
93 |
threads << Thread.new do
|
|
94 |
ActiveRecord::Base.connection_pool.with_connection do
|
|
95 |
begin
|
|
96 |
ids.each do |id|
|
|
97 |
Issue.find(id).update(parent_id: nil)
|
|
98 |
end
|
|
99 |
rescue => e
|
|
100 |
Thread.current[:exception] = e.message
|
|
101 |
end
|
|
102 |
end
|
|
103 |
end
|
|
104 |
end
|
|
105 |
|
|
106 |
threads.each do |thread|
|
|
107 |
thread.join
|
|
108 |
assert_nil thread[:exception]
|
|
109 |
end
|
|
110 |
|
|
111 |
assert_equal 20, Issue.where(parent_id: root.id).count
|
|
112 |
Issue.where(id: ids_to_remove).each do |issue|
|
|
113 |
assert_nil issue.parent_id
|
|
114 |
assert_equal issue.id, issue.root_id
|
|
115 |
assert_equal 1, issue.lft
|
|
116 |
assert_equal 2, issue.rgt
|
|
117 |
end
|
|
118 |
|
|
119 |
root.reload
|
|
120 |
assert_equal [1, 42], [root.lft, root.rgt]
|
|
121 |
children_bounds = root.children.sort_by(&:lft).map {|c| [c.lft, c.rgt]}.flatten
|
|
122 |
assert_equal (2..41).to_a, children_bounds
|
|
123 |
|
|
124 |
end
|
|
125 |
end
|
|
126 |
|
| 77 |
127 |
private
|
| 78 |
128 |
|
| 79 |
129 |
def threaded(count, &block)
|