Skip to content
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
9 changes: 4 additions & 5 deletions app/models/concerns/namespace_parent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ module NamespaceParent

def ensure_namespace
return namespace if namespace.present?
return build_namespace unless persisted?

ns = build_namespace
if persisted?
ns.save
ns.ensure_personal_namespace_administrator! if ns.user_type?
end
ns = Namespace.create_or_find_by(parent: self)
association(:namespace).target = ns
ns.ensure_personal_namespace_administrator! if ns.user_type?
ns
end
end
27 changes: 27 additions & 0 deletions spec/models/concerns/namespace_parent_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe NamespaceParent do
describe '#ensure_namespace', :disable_transaction do
let!(:user) { create(:user) }
let(:thread_count) { [ActiveRecord::Base.connection_pool.size - 1, 2].max }

it 'creates exactly one namespace when called concurrently from separate connections' do
barrier = Concurrent::CyclicBarrier.new(thread_count)

results = Array.new(thread_count) do
Thread.new do
ActiveRecord::Base.connection_pool.with_connection do
barrier.wait
User.find(user.id).ensure_namespace
end
end
end.map(&:value)

expect(results).to all(be_a(Namespace))
expect(results.map(&:id).uniq.size).to eq(1)
expect(Namespace.where(parent: user).count).to eq(1)
end
end
end