Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
6b19945915
commit
59b0e2f45d
|
|
@ -7,7 +7,8 @@ class CustomerRelations::Contact < ApplicationRecord
|
|||
|
||||
belongs_to :group, -> { where(type: Group.sti_name) }, foreign_key: 'group_id'
|
||||
belongs_to :organization, optional: true
|
||||
has_and_belongs_to_many :issues, join_table: :issue_customer_relations_contacts # rubocop: disable Rails/HasAndBelongsToMany
|
||||
has_many :issue_contacts, inverse_of: :contact
|
||||
has_many :issues, through: :issue_contacts, inverse_of: :customer_relations_contacts
|
||||
|
||||
strip_attributes! :phone, :first_name, :last_name
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CustomerRelations::IssueContact < ApplicationRecord
|
||||
self.table_name = "issue_customer_relations_contacts"
|
||||
|
||||
belongs_to :issue, optional: false, inverse_of: :customer_relations_contacts
|
||||
belongs_to :contact, optional: false, inverse_of: :issue_contacts
|
||||
|
||||
validate :contact_belongs_to_issue_group
|
||||
|
||||
private
|
||||
|
||||
def contact_belongs_to_issue_group
|
||||
return unless contact&.group_id
|
||||
return unless issue&.project&.namespace_id
|
||||
return if contact.group_id == issue.project.namespace_id
|
||||
|
||||
errors.add(:base, _('The contact does not belong to the same group as the issue.'))
|
||||
end
|
||||
end
|
||||
|
|
@ -81,7 +81,8 @@ class Issue < ApplicationRecord
|
|||
has_and_belongs_to_many :self_managed_prometheus_alert_events, join_table: :issues_self_managed_prometheus_alert_events # rubocop: disable Rails/HasAndBelongsToMany
|
||||
has_and_belongs_to_many :prometheus_alert_events, join_table: :issues_prometheus_alert_events # rubocop: disable Rails/HasAndBelongsToMany
|
||||
has_many :prometheus_alerts, through: :prometheus_alert_events
|
||||
has_and_belongs_to_many :customer_relations_contacts, join_table: :issue_customer_relations_contacts, class_name: 'CustomerRelations::Contact' # rubocop: disable Rails/HasAndBelongsToMany
|
||||
has_many :issue_customer_relations_contacts, class_name: 'CustomerRelations::IssueContact', inverse_of: :issue
|
||||
has_many :customer_relations_contacts, through: :issue_customer_relations_contacts, source: :contact, class_name: 'CustomerRelations::Contact', inverse_of: :issues
|
||||
|
||||
accepts_nested_attributes_for :issuable_severity, update_only: true
|
||||
accepts_nested_attributes_for :sentry_issue
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
= html_escape(_('From %{code_open}%{source_title}%{code_close} into')) % { source_title: source_title, code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
|
||||
|
||||
- if issuable.new_record?
|
||||
%code#js-target-branch-title= target_title
|
||||
%code#js-target-branch-title{ data: { branch_name: @merge_request.target_branch } }= target_title
|
||||
|
||||
= link_to _('Change branches'), mr_change_branches_path(issuable)
|
||||
- elsif issuable.for_fork?
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class FixDoubleEntriesInPostgresIndexView < Gitlab::Database::Migration[1.0]
|
||||
def up
|
||||
execute(<<~SQL)
|
||||
DROP VIEW IF EXISTS postgres_indexes;
|
||||
|
||||
CREATE VIEW postgres_indexes AS
|
||||
SELECT (pg_namespace.nspname::text || '.'::text) || i.relname::text AS identifier,
|
||||
pg_index.indexrelid,
|
||||
pg_namespace.nspname AS schema,
|
||||
i.relname AS name,
|
||||
pg_indexes.tablename,
|
||||
a.amname AS type,
|
||||
pg_index.indisunique AS "unique",
|
||||
pg_index.indisvalid AS valid_index,
|
||||
i.relispartition AS partitioned,
|
||||
pg_index.indisexclusion AS exclusion,
|
||||
pg_index.indexprs IS NOT NULL AS expression,
|
||||
pg_index.indpred IS NOT NULL AS partial,
|
||||
pg_indexes.indexdef AS definition,
|
||||
pg_relation_size(i.oid::regclass) AS ondisk_size_bytes
|
||||
FROM pg_index
|
||||
JOIN pg_class i ON i.oid = pg_index.indexrelid
|
||||
JOIN pg_namespace ON i.relnamespace = pg_namespace.oid
|
||||
JOIN pg_indexes ON i.relname = pg_indexes.indexname AND pg_namespace.nspname = pg_indexes.schemaname
|
||||
JOIN pg_am a ON i.relam = a.oid
|
||||
WHERE pg_namespace.nspname <> 'pg_catalog'::name AND (pg_namespace.nspname = ANY (ARRAY["current_schema"(), 'gitlab_partitions_dynamic'::name, 'gitlab_partitions_static'::name]));
|
||||
SQL
|
||||
end
|
||||
|
||||
def down
|
||||
execute(<<~SQL)
|
||||
DROP VIEW IF EXISTS postgres_indexes;
|
||||
|
||||
CREATE VIEW postgres_indexes AS
|
||||
SELECT (pg_namespace.nspname::text || '.'::text) || i.relname::text AS identifier,
|
||||
pg_index.indexrelid,
|
||||
pg_namespace.nspname AS schema,
|
||||
i.relname AS name,
|
||||
pg_indexes.tablename,
|
||||
a.amname AS type,
|
||||
pg_index.indisunique AS "unique",
|
||||
pg_index.indisvalid AS valid_index,
|
||||
i.relispartition AS partitioned,
|
||||
pg_index.indisexclusion AS exclusion,
|
||||
pg_index.indexprs IS NOT NULL AS expression,
|
||||
pg_index.indpred IS NOT NULL AS partial,
|
||||
pg_indexes.indexdef AS definition,
|
||||
pg_relation_size(i.oid::regclass) AS ondisk_size_bytes
|
||||
FROM pg_index
|
||||
JOIN pg_class i ON i.oid = pg_index.indexrelid
|
||||
JOIN pg_namespace ON i.relnamespace = pg_namespace.oid
|
||||
JOIN pg_indexes ON i.relname = pg_indexes.indexname
|
||||
JOIN pg_am a ON i.relam = a.oid
|
||||
WHERE pg_namespace.nspname <> 'pg_catalog'::name AND (pg_namespace.nspname = ANY (ARRAY["current_schema"(), 'gitlab_partitions_dynamic'::name, 'gitlab_partitions_static'::name]));
|
||||
SQL
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
168b383c4a85de35ade8a26e442ca49a40342ba05fb23fab4f0444814d976f65
|
||||
|
|
@ -17661,7 +17661,7 @@ CREATE VIEW postgres_indexes AS
|
|||
FROM ((((pg_index
|
||||
JOIN pg_class i ON ((i.oid = pg_index.indexrelid)))
|
||||
JOIN pg_namespace ON ((i.relnamespace = pg_namespace.oid)))
|
||||
JOIN pg_indexes ON ((i.relname = pg_indexes.indexname)))
|
||||
JOIN pg_indexes ON (((i.relname = pg_indexes.indexname) AND (pg_namespace.nspname = pg_indexes.schemaname))))
|
||||
JOIN pg_am a ON ((i.relam = a.oid)))
|
||||
WHERE ((pg_namespace.nspname <> 'pg_catalog'::name) AND (pg_namespace.nspname = ANY (ARRAY["current_schema"(), 'gitlab_partitions_dynamic'::name, 'gitlab_partitions_static'::name])));
|
||||
|
||||
|
|
|
|||
|
|
@ -400,11 +400,12 @@ Retrieve the job that generated a job token.
|
|||
GET /job
|
||||
```
|
||||
|
||||
Examples
|
||||
Examples (must run as part of the [`script`](../ci/yaml/index.md#script) section of a [CI/CD job](../ci/jobs/index.md)):
|
||||
|
||||
```shell
|
||||
curl --header "JOB-TOKEN: <your_job_token>" "https://gitlab.example.com/api/v4/job"
|
||||
curl "https://gitlab.example.com/api/v4/job?job_token=<your_job_token>"
|
||||
curl --header "Authorization: Bearer $CI_JOB_TOKEN" "${CI_API_V4_URL}/job"
|
||||
curl --header "JOB-TOKEN: $CI_JOB_TOKEN" "${CI_API_V4_URL}/job"
|
||||
curl "${CI_API_V4_URL}/job?job_token=$CI_JOB_TOKEN"
|
||||
```
|
||||
|
||||
Example of response
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ GitLab administrators can still update the default branch protection of a group.
|
|||
## Define which roles can create projects
|
||||
|
||||
Instance-level protections for project creation define which roles can
|
||||
[add projects to a group](../../group/index.md#specify-who-can-add-projects-to-a-group)]
|
||||
[add projects to a group](../../group/index.md#specify-who-can-add-projects-to-a-group)
|
||||
on the instance. To alter which roles have permission to create projects:
|
||||
|
||||
1. Sign in to GitLab as a user with [Administrator role](../../permissions.md).
|
||||
|
|
|
|||
|
|
@ -784,6 +784,12 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
|
||||
def list_refs
|
||||
wrapped_gitaly_errors do
|
||||
gitaly_ref_client.list_refs
|
||||
end
|
||||
end
|
||||
|
||||
# Refactoring aid; allows us to copy code from app/models/repository.rb
|
||||
def commit(ref = 'HEAD')
|
||||
Gitlab::Git::Commit.find(self, ref)
|
||||
|
|
|
|||
|
|
@ -194,6 +194,16 @@ module Gitlab
|
|||
raise ArgumentError, ex
|
||||
end
|
||||
|
||||
def list_refs(patterns = [Gitlab::Git::BRANCH_REF_PREFIX])
|
||||
request = Gitaly::ListRefsRequest.new(
|
||||
repository: @gitaly_repo,
|
||||
patterns: patterns
|
||||
)
|
||||
|
||||
response = GitalyClient.call(@storage, :ref_service, :list_refs, request, timeout: GitalyClient.fast_timeout)
|
||||
consume_list_refs_response(response)
|
||||
end
|
||||
|
||||
def pack_refs
|
||||
request = Gitaly::PackRefsRequest.new(repository: @gitaly_repo)
|
||||
|
||||
|
|
@ -206,6 +216,10 @@ module Gitlab
|
|||
response.flat_map { |message| message.names.map { |name| yield(name) } }
|
||||
end
|
||||
|
||||
def consume_list_refs_response(response)
|
||||
response.flat_map(&:references)
|
||||
end
|
||||
|
||||
def sort_local_branches_by_param(sort_by)
|
||||
sort_by = 'name' if sort_by == 'name_asc'
|
||||
|
||||
|
|
|
|||
|
|
@ -30434,6 +30434,9 @@ msgstr ""
|
|||
msgid "SecurityReports|Create issue"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Create policy"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Development vulnerabilities"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -30491,6 +30494,15 @@ msgstr ""
|
|||
msgid "SecurityReports|Manage and track vulnerabilities identified in projects within your group. Vulnerabilities in projects are shown here when security testing is configured."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Manage and track vulnerabilities identified in your Kubernetes clusters. Vulnerabilities appear here after you create a scan execution policy in any project in this group."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Manage and track vulnerabilities identified in your Kubernetes clusters. Vulnerabilities appear here after you create a scan execution policy in any project in this instance."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Manage and track vulnerabilities identified in your Kubernetes clusters. Vulnerabilities appear here after you create a scan execution policy in this project."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Manage and track vulnerabilities identified in your project. Vulnerabilities are shown here when security testing is configured."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -30500,6 +30512,9 @@ msgstr ""
|
|||
msgid "SecurityReports|Maximum selected projects limit reached"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Monitor vulnerabilities across clusters"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityReports|Monitor vulnerabilities in all of your projects"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -33861,6 +33876,9 @@ msgstr ""
|
|||
msgid "The connection will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
|
||||
msgstr ""
|
||||
|
||||
msgid "The contact does not belong to the same group as the issue."
|
||||
msgstr ""
|
||||
|
||||
msgid "The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :issue_customer_relations_contact, class: 'CustomerRelations::IssueContact' do
|
||||
issue { association(:issue, project: project) }
|
||||
contact { association(:contact, group: group) }
|
||||
|
||||
transient do
|
||||
group { association(:group) }
|
||||
project { association(:project, group: group) }
|
||||
end
|
||||
|
||||
trait :for_contact do
|
||||
issue { association(:issue, project: project) }
|
||||
contact { raise ArgumentError, '`contact` is manadatory' }
|
||||
|
||||
transient do
|
||||
project { association(:project, group: contact.group) }
|
||||
end
|
||||
end
|
||||
|
||||
trait :for_issue do
|
||||
issue { raise ArgumentError, '`issue` is manadatory' }
|
||||
contact { association(:contact, group: issue.project.group) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -22,6 +22,8 @@ RSpec.describe 'factories' do
|
|||
[:debian_project_component_file, :object_storage],
|
||||
[:debian_project_distribution, :object_storage],
|
||||
[:debian_file_metadatum, :unknown],
|
||||
[:issue_customer_relations_contact, :for_contact],
|
||||
[:issue_customer_relations_contact, :for_issue],
|
||||
[:package_file, :object_storage],
|
||||
[:pages_domain, :without_certificate],
|
||||
[:pages_domain, :without_key],
|
||||
|
|
@ -72,6 +74,7 @@ RSpec.describe 'factories' do
|
|||
fork_network_member
|
||||
group_member
|
||||
import_state
|
||||
issue_customer_relations_contact
|
||||
milestone_release
|
||||
namespace
|
||||
project_broken_repo
|
||||
|
|
|
|||
|
|
@ -873,45 +873,65 @@ RSpec.describe Gitlab::Auth::AuthFinders do
|
|||
end
|
||||
|
||||
describe '#find_user_from_job_token' do
|
||||
let(:token) { job.token }
|
||||
|
||||
subject { find_user_from_job_token }
|
||||
|
||||
context 'when the token is in the headers' do
|
||||
before do
|
||||
set_header(described_class::JOB_TOKEN_HEADER, token)
|
||||
shared_examples 'finds user when job token allowed' do
|
||||
context 'when the token is in the headers' do
|
||||
before do
|
||||
set_header(described_class::JOB_TOKEN_HEADER, token)
|
||||
end
|
||||
|
||||
it_behaves_like 'find user from job token'
|
||||
end
|
||||
|
||||
it_behaves_like 'find user from job token'
|
||||
end
|
||||
context 'when the token is in the job_token param' do
|
||||
before do
|
||||
set_param(described_class::JOB_TOKEN_PARAM, token)
|
||||
end
|
||||
|
||||
context 'when the token is in the job_token param' do
|
||||
before do
|
||||
set_param(described_class::JOB_TOKEN_PARAM, token)
|
||||
it_behaves_like 'find user from job token'
|
||||
end
|
||||
|
||||
it_behaves_like 'find user from job token'
|
||||
end
|
||||
context 'when the token is in the token param' do
|
||||
before do
|
||||
set_param(described_class::RUNNER_JOB_TOKEN_PARAM, token)
|
||||
end
|
||||
|
||||
context 'when the token is in the token param' do
|
||||
before do
|
||||
set_param(described_class::RUNNER_JOB_TOKEN_PARAM, token)
|
||||
it_behaves_like 'find user from job token'
|
||||
end
|
||||
|
||||
it_behaves_like 'find user from job token'
|
||||
end
|
||||
|
||||
context 'when the job token is provided via basic auth' do
|
||||
context 'when route setting allows job_token' do
|
||||
let(:route_authentication_setting) { { job_token_allowed: true } }
|
||||
|
||||
include_examples 'finds user when job token allowed'
|
||||
end
|
||||
|
||||
context 'when route setting is basic auth' do
|
||||
let(:route_authentication_setting) { { job_token_allowed: :basic_auth } }
|
||||
let(:username) { ::Gitlab::Auth::CI_JOB_USER }
|
||||
let(:token) { job.token }
|
||||
|
||||
before do
|
||||
set_basic_auth_header(username, token)
|
||||
context 'when the token is provided via basic auth' do
|
||||
let(:username) { ::Gitlab::Auth::CI_JOB_USER }
|
||||
|
||||
before do
|
||||
set_basic_auth_header(username, token)
|
||||
end
|
||||
|
||||
it { is_expected.to eq(user) }
|
||||
end
|
||||
|
||||
it { is_expected.to eq(user) }
|
||||
include_examples 'finds user when job token allowed'
|
||||
end
|
||||
|
||||
context 'credentials are provided but route setting is incorrect' do
|
||||
let(:route_authentication_setting) { { job_token_allowed: :unknown } }
|
||||
context 'when route setting job_token_allowed is invalid' do
|
||||
let(:route_authentication_setting) { { job_token_allowed: false } }
|
||||
|
||||
context 'when the token is provided' do
|
||||
before do
|
||||
set_header(described_class::JOB_TOKEN_HEADER, token)
|
||||
end
|
||||
|
||||
it { is_expected.to be_nil }
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1888,6 +1888,18 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#list_refs' do
|
||||
it 'returns a list of branches with their head commit' do
|
||||
refs = repository.list_refs
|
||||
reference = refs.first
|
||||
|
||||
expect(refs).to be_an(Enumerable)
|
||||
expect(reference).to be_a(Gitaly::ListRefsResponse::Reference)
|
||||
expect(reference.name).to be_a(String)
|
||||
expect(reference.target).to be_a(String)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#set_full_path' do
|
||||
before do
|
||||
repository_rugged.config["gitlab.fullpath"] = repository_path
|
||||
|
|
|
|||
|
|
@ -252,6 +252,26 @@ RSpec.describe Gitlab::GitalyClient::RefService do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#list_refs' do
|
||||
it 'sends a list_refs message' do
|
||||
expect_any_instance_of(Gitaly::RefService::Stub)
|
||||
.to receive(:list_refs)
|
||||
.with(gitaly_request_with_params(patterns: ['refs/heads/']), kind_of(Hash))
|
||||
.and_call_original
|
||||
|
||||
client.list_refs
|
||||
end
|
||||
|
||||
it 'accepts a patterns argument' do
|
||||
expect_any_instance_of(Gitaly::RefService::Stub)
|
||||
.to receive(:list_refs)
|
||||
.with(gitaly_request_with_params(patterns: ['refs/tags/']), kind_of(Hash))
|
||||
.and_call_original
|
||||
|
||||
client.list_refs([Gitlab::Git::TAG_REF_PREFIX])
|
||||
end
|
||||
end
|
||||
|
||||
describe '#pack_refs' do
|
||||
it 'sends a pack_refs message' do
|
||||
expect_any_instance_of(Gitaly::RefService::Stub)
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ issues:
|
|||
- incident_management_issuable_escalation_status
|
||||
- pending_escalations
|
||||
- customer_relations_contacts
|
||||
- issue_customer_relations_contacts
|
||||
work_item_type:
|
||||
- issues
|
||||
events:
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ RSpec.describe CustomerRelations::Contact, type: :model do
|
|||
describe 'associations' do
|
||||
it { is_expected.to belong_to(:group) }
|
||||
it { is_expected.to belong_to(:organization).optional }
|
||||
it { is_expected.to have_and_belong_to_many(:issues) }
|
||||
it { is_expected.to have_many(:issue_contacts) }
|
||||
it { is_expected.to have_many(:issues) }
|
||||
end
|
||||
|
||||
describe 'validations' do
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe CustomerRelations::IssueContact do
|
||||
let_it_be(:issue_contact, reload: true) { create(:issue_customer_relations_contact) }
|
||||
|
||||
subject { issue_contact }
|
||||
|
||||
it { expect(subject).to be_valid }
|
||||
|
||||
describe 'associations' do
|
||||
it { is_expected.to belong_to(:issue).required }
|
||||
it { is_expected.to belong_to(:contact).required }
|
||||
end
|
||||
|
||||
describe 'factory' do
|
||||
let(:built) { build(:issue_customer_relations_contact) }
|
||||
let(:stubbed) { build_stubbed(:issue_customer_relations_contact) }
|
||||
let(:created) { create(:issue_customer_relations_contact) }
|
||||
|
||||
let(:group) { build(:group) }
|
||||
let(:project) { build(:project, group: group) }
|
||||
let(:issue) { build(:issue, project: project) }
|
||||
let(:contact) { build(:contact, group: group) }
|
||||
let(:for_issue) { build(:issue_customer_relations_contact, :for_issue, issue: issue) }
|
||||
let(:for_contact) { build(:issue_customer_relations_contact, :for_contact, contact: contact) }
|
||||
|
||||
it 'uses objects from the same group', :aggregate_failures do
|
||||
expect(stubbed.contact.group).to eq(stubbed.issue.project.group)
|
||||
expect(built.contact.group).to eq(built.issue.project.group)
|
||||
expect(created.contact.group).to eq(created.issue.project.group)
|
||||
end
|
||||
|
||||
it 'builds using the same group', :aggregate_failures do
|
||||
expect(for_issue.contact.group).to eq(group)
|
||||
expect(for_contact.issue.project.group).to eq(group)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'validation' do
|
||||
let(:built) { build(:issue_customer_relations_contact, issue: create(:issue), contact: create(:contact)) }
|
||||
|
||||
it 'fails when the contact group does not match the issue group' do
|
||||
expect(built).not_to be_valid
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -34,7 +34,8 @@ RSpec.describe Issue do
|
|||
it { is_expected.to have_many(:issue_email_participants) }
|
||||
it { is_expected.to have_many(:timelogs).autosave(true) }
|
||||
it { is_expected.to have_one(:incident_management_issuable_escalation_status) }
|
||||
it { is_expected.to have_and_belong_to_many(:customer_relations_contacts) }
|
||||
it { is_expected.to have_many(:issue_customer_relations_contacts) }
|
||||
it { is_expected.to have_many(:customer_relations_contacts) }
|
||||
|
||||
describe 'versions.most_recent' do
|
||||
it 'returns the most recent version' do
|
||||
|
|
|
|||
|
|
@ -429,11 +429,11 @@ RSpec.describe 'getting an issue list for a project' do
|
|||
end
|
||||
|
||||
it 'avoids N+1 queries' do
|
||||
create(:contact, group_id: group.id, issues: [issue_a])
|
||||
create(:issue_customer_relations_contact, :for_issue, issue: issue_a)
|
||||
|
||||
control = ActiveRecord::QueryRecorder.new(skip_cached: false) { clean_state_query }
|
||||
|
||||
create(:contact, group_id: group.id, issues: [issue_a])
|
||||
create(:issue_customer_relations_contact, :for_issue, issue: issue_a)
|
||||
|
||||
expect { clean_state_query }.not_to exceed_all_query_limit(control)
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue