project_nested_set_concurrency_test.rb 2.36 KB
Newer Older
1
# frozen_string_literal: true
2

3
# Redmine - project management software
jplang's avatar
jplang committed
4
# Copyright (C) 2006-2017  Jean-Philippe Lang
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

require File.expand_path('../../test_helper', __FILE__)

class ProjectNestedSetConcurrencyTest < ActiveSupport::TestCase
23
  self.use_transactional_tests = false
24 25

  def setup
26
    User.current = nil
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
    CustomField.delete_all
  end

  def teardown
    Project.delete_all
  end

  def test_concurrency
    skip if sqlite?
    # Generates a project and destroys it in order
    # to load all needed classes before starting threads
    p = generate_project!
    p.destroy

    assert_difference 'Project.count', 60 do
      threads = []
      3.times do |i|
        threads << Thread.new(i) do
          ActiveRecord::Base.connection_pool.with_connection do
            begin
              10.times do
                p = generate_project!
                c1 = generate_project! :parent_id => p.id
                c2 = generate_project! :parent_id => p.id
                c3 = generate_project! :parent_id => p.id
                c2.reload.destroy
                c1.reload.destroy
              end
            rescue Exception => e
              Thread.current[:exception] = e.message
            end
          end
        end
      end
      threads.each do |thread|
        thread.join
        assert_nil thread[:exception]
      end
    end
  end

  # Generates a bare project with random name
  # and identifier
  def generate_project!(attributes={})
    identifier = "a"+Redmine::Utils.random_hex(6)
    Project.generate!({
        :identifier => identifier,
        :name => identifier,
        :tracker_ids => [],
        :enabled_module_names => []
      }.merge(attributes))
  end
end