Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-08-12 21:10:45 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-08-12 21:10:45 +0300
commitbf1990164b801489b4475504701eefb66146e724 (patch)
treeb21f9118116f413cdbde621048bd9b93c1388424 /spec
parentdc250651ab26bf7bce9205d5fa4a45dd58e2df81 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/db/schema_spec.rb3
-rw-r--r--spec/features/clusters/cluster_health_dashboard_spec.rb2
-rw-r--r--spec/finders/issues_finder_spec.rb162
-rw-r--r--spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric.yml2
-rw-r--r--spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric_with_ee.yml2
-rw-r--r--spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric_with_name_suggestions.yml2
-rw-r--r--spec/frontend/environments/environments_app_spec.js50
-rw-r--r--spec/frontend/terraform/components/states_table_actions_spec.js2
-rw-r--r--spec/graphql/mutations/design_management/delete_spec.rb39
-rw-r--r--spec/graphql/resolvers/issues_resolver_spec.rb6
-rw-r--r--spec/lib/gitlab/background_migration/copy_ci_builds_columns_to_security_scans_spec.rb51
-rw-r--r--spec/lib/gitlab/usage/docs/helper_spec.rb4
-rw-r--r--spec/lib/gitlab/usage/metric_definition_spec.rb4
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/collected_data_categories_metric_spec.rb2
-rw-r--r--spec/lib/gitlab/usage_data_metrics_spec.rb162
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb2
-rw-r--r--spec/migrations/schedule_copy_ci_builds_columns_to_security_scans_spec.rb43
-rw-r--r--spec/models/issue_spec.rb59
-rw-r--r--spec/policies/issue_policy_spec.rb15
-rw-r--r--spec/services/service_ping/permit_data_categories_service_spec.rb2
-rw-r--r--spec/support/shared_contexts/services/service_ping/stubbed_service_ping_metrics_definitions_shared_context.rb8
21 files changed, 428 insertions, 194 deletions
diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb
index 18f2f7b54c4..7e4b8c53885 100644
--- a/spec/db/schema_spec.rb
+++ b/spec/db/schema_spec.rb
@@ -86,7 +86,8 @@ RSpec.describe 'Database schema' do
users: %w[color_scheme_id created_by_id theme_id email_opted_in_source_id],
users_star_projects: %w[user_id],
vulnerability_identifiers: %w[external_id],
- vulnerability_scanners: %w[external_id]
+ vulnerability_scanners: %w[external_id],
+ security_scans: %w[pipeline_id] # foreign key is not added as ci_pipeline table will be moved into different db soon
}.with_indifferent_access.freeze
context 'for table' do
diff --git a/spec/features/clusters/cluster_health_dashboard_spec.rb b/spec/features/clusters/cluster_health_dashboard_spec.rb
index 32caad775e4..e4a36f654e5 100644
--- a/spec/features/clusters/cluster_health_dashboard_spec.rb
+++ b/spec/features/clusters/cluster_health_dashboard_spec.rb
@@ -80,7 +80,7 @@ RSpec.describe 'Cluster Health board', :js, :kubeclient, :use_clean_rails_memory
expect(page).to have_content('Avg')
end
- it 'focuses the single panel on toggle' do
+ it 'focuses the single panel on toggle', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/338341' do
click_button('More actions')
click_button('Expand panel')
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index 1c8c2af8e03..0cb73f3da6d 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -789,7 +789,7 @@ RSpec.describe IssuesFinder do
context 'user filters confidential issues' do
let(:params) { { confidential: true } }
- it 'returns only confdential issues' do
+ it 'returns only confidential issues' do
expect(issues).to contain_exactly(confidential_issue)
end
end
@@ -797,7 +797,7 @@ RSpec.describe IssuesFinder do
context 'user filters only public issues' do
let(:params) { { confidential: false } }
- it 'returns only confdential issues' do
+ it 'returns only public issues' do
expect(issues).to contain_exactly(issue1, issue2, issue3, issue4, issue5)
end
end
@@ -1004,9 +1004,38 @@ RSpec.describe IssuesFinder do
let(:guest) { create(:user) }
let_it_be(:authorized_user) { create(:user) }
+ let_it_be(:banned_user) { create(:user, :banned) }
let_it_be(:project) { create(:project, namespace: authorized_user.namespace) }
let_it_be(:public_issue) { create(:issue, project: project) }
let_it_be(:confidential_issue) { create(:issue, project: project, confidential: true) }
+ let_it_be(:hidden_issue) { create(:issue, project: project, author: banned_user) }
+
+ shared_examples 'returns public, does not return hidden or confidential' do
+ it 'returns only public issues' do
+ expect(subject).to include(public_issue)
+ expect(subject).not_to include(confidential_issue, hidden_issue)
+ end
+ end
+
+ shared_examples 'returns public and confidential, does not return hidden' do
+ it 'returns only public and confidential issues' do
+ expect(subject).to include(public_issue, confidential_issue)
+ expect(subject).not_to include(hidden_issue)
+ end
+ end
+
+ shared_examples 'returns public and hidden, does not return confidential' do
+ it 'returns only public and hidden issues' do
+ expect(subject).to include(public_issue, hidden_issue)
+ expect(subject).not_to include(confidential_issue)
+ end
+ end
+
+ shared_examples 'returns public, confidential, and hidden' do
+ it 'returns all issues' do
+ expect(subject).to include(public_issue, confidential_issue, hidden_issue)
+ end
+ end
context 'when no project filter is given' do
let(:params) { {} }
@@ -1014,18 +1043,28 @@ RSpec.describe IssuesFinder do
context 'for an anonymous user' do
subject { described_class.new(nil, params).with_confidentiality_access_check }
- it 'returns only public issues' do
- expect(subject).to include(public_issue)
- expect(subject).not_to include(confidential_issue)
+ it_behaves_like 'returns public, does not return hidden or confidential'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public and hidden, does not return confidential'
end
end
context 'for a user without project membership' do
subject { described_class.new(user, params).with_confidentiality_access_check }
- it 'returns only public issues' do
- expect(subject).to include(public_issue)
- expect(subject).not_to include(confidential_issue)
+ it_behaves_like 'returns public, does not return hidden or confidential'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public and hidden, does not return confidential'
end
end
@@ -1036,17 +1075,28 @@ RSpec.describe IssuesFinder do
project.add_guest(guest)
end
- it 'returns only public issues' do
- expect(subject).to include(public_issue)
- expect(subject).not_to include(confidential_issue)
+ it_behaves_like 'returns public, does not return hidden or confidential'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public and hidden, does not return confidential'
end
end
context 'for a project member with access to view confidential issues' do
subject { described_class.new(authorized_user, params).with_confidentiality_access_check }
- it 'returns all issues' do
- expect(subject).to include(public_issue, confidential_issue)
+ it_behaves_like 'returns public and confidential, does not return hidden'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public, confidential, and hidden'
end
end
@@ -1056,15 +1106,26 @@ RSpec.describe IssuesFinder do
subject { described_class.new(admin_user, params).with_confidentiality_access_check }
context 'when admin mode is enabled', :enable_admin_mode do
- it 'returns all issues' do
- expect(subject).to include(public_issue, confidential_issue)
+ it_behaves_like 'returns public, confidential, and hidden'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public, confidential, and hidden'
end
end
context 'when admin mode is disabled' do
- it 'returns only public issues' do
- expect(subject).to include(public_issue)
- expect(subject).not_to include(confidential_issue)
+ it_behaves_like 'returns public, does not return hidden or confidential'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public and hidden, does not return confidential'
end
end
end
@@ -1076,14 +1137,18 @@ RSpec.describe IssuesFinder do
context 'for an anonymous user' do
subject { described_class.new(nil, params).with_confidentiality_access_check }
- it 'returns only public issues' do
- expect(subject).to include(public_issue)
- expect(subject).not_to include(confidential_issue)
+ it_behaves_like 'returns public, does not return hidden or confidential'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public and hidden, does not return confidential'
end
it 'does not filter by confidentiality' do
expect(Issue).not_to receive(:where).with(a_string_matching('confidential'), anything)
-
subject
end
end
@@ -1091,9 +1156,14 @@ RSpec.describe IssuesFinder do
context 'for a user without project membership' do
subject { described_class.new(user, params).with_confidentiality_access_check }
- it 'returns only public issues' do
- expect(subject).to include(public_issue)
- expect(subject).not_to include(confidential_issue)
+ it_behaves_like 'returns public, does not return hidden or confidential'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public and hidden, does not return confidential'
end
it 'filters by confidentiality' do
@@ -1108,9 +1178,14 @@ RSpec.describe IssuesFinder do
project.add_guest(guest)
end
- it 'returns only public issues' do
- expect(subject).to include(public_issue)
- expect(subject).not_to include(confidential_issue)
+ it_behaves_like 'returns public, does not return hidden or confidential'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public and hidden, does not return confidential'
end
it 'filters by confidentiality' do
@@ -1121,8 +1196,14 @@ RSpec.describe IssuesFinder do
context 'for a project member with access to view confidential issues' do
subject { described_class.new(authorized_user, params).with_confidentiality_access_check }
- it 'returns all issues' do
- expect(subject).to include(public_issue, confidential_issue)
+ it_behaves_like 'returns public and confidential, does not return hidden'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public, confidential, and hidden'
end
it 'does not filter by confidentiality' do
@@ -1138,8 +1219,14 @@ RSpec.describe IssuesFinder do
subject { described_class.new(admin_user, params).with_confidentiality_access_check }
context 'when admin mode is enabled', :enable_admin_mode do
- it 'returns all issues' do
- expect(subject).to include(public_issue, confidential_issue)
+ it_behaves_like 'returns public, confidential, and hidden'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public, confidential, and hidden'
end
it 'does not filter by confidentiality' do
@@ -1150,9 +1237,14 @@ RSpec.describe IssuesFinder do
end
context 'when admin mode is disabled' do
- it 'returns only public issues' do
- expect(subject).to include(public_issue)
- expect(subject).not_to include(confidential_issue)
+ it_behaves_like 'returns public, does not return hidden or confidential'
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it_behaves_like 'returns public and hidden, does not return confidential'
end
it 'filters by confidentiality' do
diff --git a/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric.yml b/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric.yml
index af5704f7d01..8495d983d10 100644
--- a/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric.yml
+++ b/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric.yml
@@ -12,7 +12,7 @@ milestone: "13.9"
introduced_by_url:
time_frame: 7d
data_source:
-data_category: Operational
+data_category: operational
performance_indicator_type:
distribution:
- ce
diff --git a/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric_with_ee.yml b/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric_with_ee.yml
index 6f4e2b3f9ee..82e9af5b04f 100644
--- a/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric_with_ee.yml
+++ b/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric_with_ee.yml
@@ -12,7 +12,7 @@ milestone: "13.9"
introduced_by_url:
time_frame: 7d
data_source:
-data_category: Optional
+data_category: optional
performance_indicator_type:
distribution:
- ee
diff --git a/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric_with_name_suggestions.yml b/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric_with_name_suggestions.yml
index a0e5ea799a5..aad7dc76290 100644
--- a/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric_with_name_suggestions.yml
+++ b/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric_with_name_suggestions.yml
@@ -13,7 +13,7 @@ milestone: "13.9"
introduced_by_url:
time_frame: 7d
data_source:
-data_category: Optional
+data_category: optional
performance_indicator_type:
distribution:
- ce
diff --git a/spec/frontend/environments/environments_app_spec.js b/spec/frontend/environments/environments_app_spec.js
index 1abdeff614c..dc176001943 100644
--- a/spec/frontend/environments/environments_app_spec.js
+++ b/spec/frontend/environments/environments_app_spec.js
@@ -1,4 +1,4 @@
-import { GlTabs } from '@gitlab/ui';
+import { GlTabs, GlAlert } from '@gitlab/ui';
import { mount, shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
@@ -7,7 +7,9 @@ import DeployBoard from '~/environments/components/deploy_board.vue';
import EmptyState from '~/environments/components/empty_state.vue';
import EnableReviewAppModal from '~/environments/components/enable_review_app_modal.vue';
import EnvironmentsApp from '~/environments/components/environments_app.vue';
+import { ENVIRONMENTS_SURVEY_DISMISSED_COOKIE_NAME } from '~/environments/constants';
import axios from '~/lib/utils/axios_utils';
+import { setCookie, getCookie, removeCookie } from '~/lib/utils/common_utils';
import * as urlUtils from '~/lib/utils/url_utility';
import { environment, folder } from './mock_data';
@@ -48,6 +50,7 @@ describe('Environment', () => {
const findNewEnvironmentButton = () => wrapper.findByTestId('new-environment');
const findEnvironmentsTabAvailable = () => wrapper.find('.js-environments-tab-available > a');
const findEnvironmentsTabStopped = () => wrapper.find('.js-environments-tab-stopped > a');
+ const findSurveyAlert = () => wrapper.find(GlAlert);
beforeEach(() => {
mock = new MockAdapter(axios);
@@ -280,4 +283,49 @@ describe('Environment', () => {
expect(wrapper.findComponent(GlTabs).attributes('value')).toBe('1');
});
});
+
+ describe('survey alert', () => {
+ beforeEach(async () => {
+ mockRequest(200, { environments: [] });
+ await createWrapper(true);
+ });
+
+ afterEach(() => {
+ removeCookie(ENVIRONMENTS_SURVEY_DISMISSED_COOKIE_NAME);
+ });
+
+ describe('when the user has not dismissed the alert', () => {
+ it('shows the alert', () => {
+ expect(findSurveyAlert().exists()).toBe(true);
+ });
+
+ describe('when the user dismisses the alert', () => {
+ beforeEach(() => {
+ findSurveyAlert().vm.$emit('dismiss');
+ });
+
+ it('hides the alert', () => {
+ expect(findSurveyAlert().exists()).toBe(false);
+ });
+
+ it('persists the dismisal using a cookie', () => {
+ const cookieValue = getCookie(ENVIRONMENTS_SURVEY_DISMISSED_COOKIE_NAME);
+
+ expect(cookieValue).toBe('true');
+ });
+ });
+ });
+
+ describe('when the user has previously dismissed the alert', () => {
+ beforeEach(async () => {
+ setCookie(ENVIRONMENTS_SURVEY_DISMISSED_COOKIE_NAME, 'true');
+
+ await createWrapper(true);
+ });
+
+ it('does not show the alert', () => {
+ expect(findSurveyAlert().exists()).toBe(false);
+ });
+ });
+ });
});
diff --git a/spec/frontend/terraform/components/states_table_actions_spec.js b/spec/frontend/terraform/components/states_table_actions_spec.js
index 34e7d597cd8..9d28e8ce294 100644
--- a/spec/frontend/terraform/components/states_table_actions_spec.js
+++ b/spec/frontend/terraform/components/states_table_actions_spec.js
@@ -275,7 +275,7 @@ describe('StatesTableActions', () => {
it('displays a remove modal', () => {
expect(findRemoveModal().text()).toContain(
- `You are about to remove the State file ${defaultProps.state.name}`,
+ `You are about to remove the state file ${defaultProps.state.name}`,
);
});
diff --git a/spec/graphql/mutations/design_management/delete_spec.rb b/spec/graphql/mutations/design_management/delete_spec.rb
index 3efa865c64b..93fff5e5103 100644
--- a/spec/graphql/mutations/design_management/delete_spec.rb
+++ b/spec/graphql/mutations/design_management/delete_spec.rb
@@ -86,9 +86,9 @@ RSpec.describe Mutations::DesignManagement::Delete do
end
end
- it 'runs no more than 28 queries' do
+ it 'runs no more than 29 queries' do
filenames.each(&:present?) # ignore setup
- # Queries: as of 2019-08-28
+ # Queries: as of 2021-07-22
# -------------
# 01. routing query
# 02. find project by id
@@ -100,25 +100,26 @@ RSpec.describe Mutations::DesignManagement::Delete do
# 09. find namespace by id
# 10. find group namespace by id
# 11. project.authorizations for user (same query as 5)
- # 12. project.project_features (same query as 3)
- # 13. project.authorizations for user (same query as 5)
- # 14. current designs by filename and issue
- # 15, 16 project.authorizations for user (same query as 5)
- # 17. find route by id and source_type
+ # 12. find user by id
+ # 13. project.project_features (same query as 3)
+ # 14. project.authorizations for user (same query as 5)
+ # 15. current designs by filename and issue
+ # 16, 17 project.authorizations for user (same query as 5)
+ # 18. find route by id and source_type
# ------------- our queries are below:
- # 18. start transaction 1
- # 19. start transaction 2
- # 20. find version by sha and issue
- # 21. exists version with sha and issue?
- # 22. leave transaction 2
- # 23. create version with sha and issue
- # 24. create design-version links
- # 25. validate version.actions.present?
- # 26. validate version.issue.present?
- # 27. validate version.sha is unique
- # 28. leave transaction 1
+ # 19. start transaction 1
+ # 20. start transaction 2
+ # 21. find version by sha and issue
+ # 22. exists version with sha and issue?
+ # 23. leave transaction 2
+ # 24. create version with sha and issue
+ # 25. create design-version links
+ # 26. validate version.actions.present?
+ # 27. validate version.issue.present?
+ # 28. validate version.sha is unique
+ # 29. leave transaction 1
#
- expect { run_mutation }.not_to exceed_query_limit(28)
+ expect { run_mutation }.not_to exceed_query_limit(29)
end
end
diff --git a/spec/graphql/resolvers/issues_resolver_spec.rb b/spec/graphql/resolvers/issues_resolver_spec.rb
index d0675633a9b..6e187e57729 100644
--- a/spec/graphql/resolvers/issues_resolver_spec.rb
+++ b/spec/graphql/resolvers/issues_resolver_spec.rb
@@ -393,13 +393,13 @@ RSpec.describe Resolvers::IssuesResolver do
end
it 'finds a specific issue with iid', :request_store do
- result = batch_sync(max_queries: 4) { resolve_issues(iid: issue1.iid).to_a }
+ result = batch_sync(max_queries: 5) { resolve_issues(iid: issue1.iid).to_a }
expect(result).to contain_exactly(issue1)
end
it 'batches queries that only include IIDs', :request_store do
- result = batch_sync(max_queries: 4) do
+ result = batch_sync(max_queries: 5) do
[issue1, issue2]
.map { |issue| resolve_issues(iid: issue.iid.to_s) }
.flat_map(&:to_a)
@@ -409,7 +409,7 @@ RSpec.describe Resolvers::IssuesResolver do
end
it 'finds a specific issue with iids', :request_store do
- result = batch_sync(max_queries: 4) do
+ result = batch_sync(max_queries: 5) do
resolve_issues(iids: [issue1.iid]).to_a
end
diff --git a/spec/lib/gitlab/background_migration/copy_ci_builds_columns_to_security_scans_spec.rb b/spec/lib/gitlab/background_migration/copy_ci_builds_columns_to_security_scans_spec.rb
new file mode 100644
index 00000000000..db822f36c21
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/copy_ci_builds_columns_to_security_scans_spec.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::CopyCiBuildsColumnsToSecurityScans, schema: 20210728174349 do
+ let(:migration) { described_class.new }
+
+ let_it_be(:namespaces) { table(:namespaces) }
+ let_it_be(:projects) { table(:projects) }
+ let_it_be(:ci_pipelines) { table(:ci_pipelines) }
+ let_it_be(:ci_builds) { table(:ci_builds) }
+ let_it_be(:security_scans) { table(:security_scans) }
+
+ let!(:namespace) { namespaces.create!(name: 'namespace', path: 'namespace') }
+ let!(:project1) { projects.create!(namespace_id: namespace.id) }
+ let!(:project2) { projects.create!(namespace_id: namespace.id) }
+ let!(:pipeline1) { ci_pipelines.create!(status: "success")}
+ let!(:pipeline2) { ci_pipelines.create!(status: "success")}
+
+ let!(:build1) { ci_builds.create!(commit_id: pipeline1.id, type: 'Ci::Build', project_id: project1.id) }
+ let!(:build2) { ci_builds.create!(commit_id: pipeline2.id, type: 'Ci::Build', project_id: project2.id) }
+ let!(:build3) { ci_builds.create!(commit_id: pipeline1.id, type: 'Ci::Build', project_id: project1.id) }
+
+ let!(:scan1) { security_scans.create!(build_id: build1.id, scan_type: 1) }
+ let!(:scan2) { security_scans.create!(build_id: build2.id, scan_type: 1) }
+ let!(:scan3) { security_scans.create!(build_id: build3.id, scan_type: 1) }
+
+ subject { migration.perform(scan1.id, scan2.id) }
+
+ before do
+ stub_const("#{described_class}::UPDATE_BATCH_SIZE", 2)
+ end
+
+ it 'copies `project_id`, `commit_id` from `ci_builds` to `security_scans`', :aggregate_failures do
+ expect(migration).to receive(:mark_job_as_succeeded).with(scan1.id, scan2.id)
+
+ subject
+
+ scan1.reload
+ expect(scan1.project_id).to eq(project1.id)
+ expect(scan1.pipeline_id).to eq(pipeline1.id)
+
+ scan2.reload
+ expect(scan2.project_id).to eq(project2.id)
+ expect(scan2.pipeline_id).to eq(pipeline2.id)
+
+ scan3.reload
+ expect(scan3.project_id).to be_nil
+ expect(scan3.pipeline_id).to be_nil
+ end
+end
diff --git a/spec/lib/gitlab/usage/docs/helper_spec.rb b/spec/lib/gitlab/usage/docs/helper_spec.rb
index e2bb1d8d818..6cff1ab4126 100644
--- a/spec/lib/gitlab/usage/docs/helper_spec.rb
+++ b/spec/lib/gitlab/usage/docs/helper_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe Gitlab::Usage::Docs::Helper do
let(:metric_definition) do
{
- data_category: 'Standard',
+ data_category: 'standard',
name: 'test_metric',
description: description,
product_group: 'group::product intelligence',
@@ -66,7 +66,7 @@ RSpec.describe Gitlab::Usage::Docs::Helper do
end
describe '#render_data_category' do
- let(:expected) { 'Data Category: `Standard`' }
+ let(:expected) { 'Data Category: `standard`' }
it { expect(helper.render_data_category(metric_definition)).to eq(expected) }
end
diff --git a/spec/lib/gitlab/usage/metric_definition_spec.rb b/spec/lib/gitlab/usage/metric_definition_spec.rb
index a7cff80e43a..1ae8a0881ef 100644
--- a/spec/lib/gitlab/usage/metric_definition_spec.rb
+++ b/spec/lib/gitlab/usage/metric_definition_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe Gitlab::Usage::MetricDefinition do
distribution: %w(ee ce),
tier: %w(free starter premium ultimate bronze silver gold),
name: 'uuid',
- data_category: 'Standard'
+ data_category: 'standard'
}
end
@@ -199,7 +199,7 @@ RSpec.describe Gitlab::Usage::MetricDefinition do
data_source: 'database',
distribution: %w(ee ce),
tier: %w(free starter premium ultimate bronze silver gold),
- data_category: 'Optional'
+ data_category: 'optional'
}
end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/collected_data_categories_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/collected_data_categories_metric_spec.rb
index 8f52d550e5c..1b2170baf17 100644
--- a/spec/lib/gitlab/usage/metrics/instrumentations/collected_data_categories_metric_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/collected_data_categories_metric_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CollectedDataCategoriesMetric do
it_behaves_like 'a correct instrumented metric value', {} do
- let(:expected_value) { %w[Standard Subscription Operational Optional] }
+ let(:expected_value) { %w[standard subscription operational optional] }
before do
allow_next_instance_of(ServicePing::PermitDataCategoriesService) do |instance|
diff --git a/spec/lib/gitlab/usage_data_metrics_spec.rb b/spec/lib/gitlab/usage_data_metrics_spec.rb
index cb3ca32b31e..7608fa7e7a0 100644
--- a/spec/lib/gitlab/usage_data_metrics_spec.rb
+++ b/spec/lib/gitlab/usage_data_metrics_spec.rb
@@ -26,130 +26,54 @@ RSpec.describe Gitlab::UsageDataMetrics do
expect(subject[:counts]).to include(:boards)
end
- it 'includes i_quickactions_approve monthly and weekly key' do
- expect(subject[:redis_hll_counters][:quickactions]).to include(:i_quickactions_approve_monthly)
- expect(subject[:redis_hll_counters][:quickactions]).to include(:i_quickactions_approve_weekly)
- end
-
- it 'includes ide_edit monthly and weekly keys' do
- expect(subject[:redis_hll_counters][:ide_edit].keys).to contain_exactly(*[
- :g_edit_by_web_ide_monthly, :g_edit_by_web_ide_weekly,
- :g_edit_by_sfe_monthly, :g_edit_by_sfe_weekly,
- :g_edit_by_sse_monthly, :g_edit_by_sse_weekly,
- :g_edit_by_snippet_ide_monthly, :g_edit_by_snippet_ide_weekly,
- :ide_edit_total_unique_counts_monthly, :ide_edit_total_unique_counts_weekly
- ])
- end
-
- it 'includes incident_management_alerts monthly and weekly keys' do
- expect(subject[:redis_hll_counters][:incident_management_alerts].keys).to contain_exactly(*[
- :incident_management_alert_create_incident_monthly, :incident_management_alert_create_incident_weekly
- ])
- end
-
- it 'includes incident_management monthly and weekly keys' do
- expect(subject[:redis_hll_counters][:incident_management]).to include(
- :incident_management_incident_created_monthly, :incident_management_incident_created_weekly,
- :incident_management_incident_reopened_monthly, :incident_management_incident_reopened_weekly,
- :incident_management_incident_closed_monthly, :incident_management_incident_closed_weekly,
- :incident_management_incident_assigned_monthly, :incident_management_incident_assigned_weekly,
- :incident_management_incident_todo_monthly, :incident_management_incident_todo_weekly,
- :incident_management_incident_comment_monthly, :incident_management_incident_comment_weekly,
- :incident_management_incident_zoom_meeting_monthly, :incident_management_incident_zoom_meeting_weekly,
- :incident_management_incident_relate_monthly, :incident_management_incident_relate_weekly,
- :incident_management_incident_unrelate_monthly, :incident_management_incident_unrelate_weekly,
- :incident_management_incident_change_confidential_monthly, :incident_management_incident_change_confidential_weekly,
- :incident_management_alert_status_changed_monthly, :incident_management_alert_status_changed_weekly,
- :incident_management_alert_assigned_monthly, :incident_management_alert_assigned_weekly,
- :incident_management_alert_todo_monthly, :incident_management_alert_todo_weekly,
- :incident_management_total_unique_counts_monthly, :incident_management_total_unique_counts_weekly
- )
- end
-
- it 'includes testing monthly and weekly keys' do
- expect(subject[:redis_hll_counters][:testing]).to include(
- :i_testing_test_case_parsed_monthly, :i_testing_test_case_parsed_weekly,
- :users_expanding_testing_code_quality_report_monthly, :users_expanding_testing_code_quality_report_weekly,
- :users_expanding_testing_accessibility_report_monthly, :users_expanding_testing_accessibility_report_weekly,
- :i_testing_summary_widget_total_monthly, :i_testing_summary_widget_total_weekly,
- :testing_total_unique_counts_monthly
- )
- end
-
- it 'includes source_code monthly and weekly keys' do
- expect(subject[:redis_hll_counters][:source_code].keys).to contain_exactly(*[
- :wiki_action_monthly, :wiki_action_weekly,
- :design_action_monthly, :design_action_weekly,
- :project_action_monthly, :project_action_weekly,
- :git_write_action_monthly, :git_write_action_weekly,
- :merge_request_action_monthly, :merge_request_action_weekly,
- :i_source_code_code_intelligence_monthly, :i_source_code_code_intelligence_weekly
- ])
- end
-
- it 'includes code_review monthly and weekly keys' do
- category = 'code_review'
- events = Gitlab::UsageDataCounters::HLLRedisCounter.known_events.select { |event| event['category'] == category}.map { |event| event['name'] }
- known_events_keys = []
- events.each do |event_name|
- known_events_keys << "#{event_name}_monthly".to_sym
- known_events_keys << "#{event_name}_weekly".to_sym
+ describe 'Redis_HLL_counters' do
+ # categories to be merged on future MR
+ let(:ignored_metric_files_key_patterns) do
+ %w(
+ analytics
+ ci_templates
+ ecosystem
+ deploy_token_packages
+ user_packages
+ epic_events
+ snippets
+ epics_usage
+ network_policies
+ ).freeze
end
- known_events_keys << "#{category}_total_unique_counts_monthly".to_sym
- known_events_keys << "#{category}_total_unique_counts_weekly".to_sym
-
- expect(subject[:redis_hll_counters][:code_review].keys).to contain_exactly(*known_events_keys)
- end
- it 'includes terraform monthly key' do
- expect(subject[:redis_hll_counters][:terraform].keys).to include(:p_terraform_state_api_unique_users_monthly)
- end
+ let(:metric_files_key_paths) do
+ Gitlab::Usage::MetricDefinition
+ .definitions
+ .select { |k, v| v.attributes[:data_source] == 'redis_hll' && v.key_path.starts_with?('redis_hll_counters') }
+ .reject { |k, v| v.key_path =~ Regexp.union(ignored_metric_files_key_patterns) }
+ .keys
+ .sort
+ end
- it 'includes terraform monthly and weekly keys' do
- expect(subject[:redis_hll_counters][:pipeline_authoring].keys).to contain_exactly(*[
- :o_pipeline_authoring_unique_users_committing_ciconfigfile_monthly, :o_pipeline_authoring_unique_users_committing_ciconfigfile_weekly,
- :o_pipeline_authoring_unique_users_pushing_mr_ciconfigfile_monthly, :o_pipeline_authoring_unique_users_pushing_mr_ciconfigfile_weekly,
- :pipeline_authoring_total_unique_counts_monthly, :pipeline_authoring_total_unique_counts_weekly
- ])
- end
+ # Recursively traverse nested Hash of a generated Usage Ping to return an Array of key paths
+ # in the dotted format used in metric definition YAML files, e.g.: 'count.category.metric_name'
+ def parse_service_ping_keys(object, key_path = [])
+ if object.is_a?(Hash)
+ object.each_with_object([]) do |(key, value), result|
+ result.append parse_service_ping_keys(value, key_path + [key])
+ end
+ else
+ key_path.join('.')
+ end
+ end
- it 'includes users_expanding_secure_security_report monthly and weekly keys' do
- expect(subject[:redis_hll_counters][:secure].keys).to contain_exactly(*[
- :users_expanding_secure_security_report_monthly, :users_expanding_secure_security_report_weekly
- ])
- end
+ let(:usage_ping_key_paths) do
+ parse_service_ping_keys(subject)
+ .flatten
+ .select { |k| k.starts_with?('redis_hll_counters') }
+ .reject {|k| k =~ Regexp.union(ignored_metric_files_key_patterns) }
+ .sort
+ end
- it 'includes issues_edit monthly and weekly keys' do
- expect(subject[:redis_hll_counters][:issues_edit].keys).to include(
- :g_project_management_issue_title_changed_monthly, :g_project_management_issue_title_changed_weekly,
- :g_project_management_issue_description_changed_monthly, :g_project_management_issue_description_changed_weekly,
- :g_project_management_issue_assignee_changed_monthly, :g_project_management_issue_assignee_changed_weekly,
- :g_project_management_issue_made_confidential_monthly, :g_project_management_issue_made_confidential_weekly,
- :g_project_management_issue_made_visible_monthly, :g_project_management_issue_made_visible_weekly,
- :g_project_management_issue_created_monthly, :g_project_management_issue_created_weekly,
- :g_project_management_issue_closed_monthly, :g_project_management_issue_closed_weekly,
- :g_project_management_issue_reopened_monthly, :g_project_management_issue_reopened_weekly,
- :g_project_management_issue_label_changed_monthly, :g_project_management_issue_label_changed_weekly,
- :g_project_management_issue_milestone_changed_monthly, :g_project_management_issue_milestone_changed_weekly,
- :g_project_management_issue_cross_referenced_monthly, :g_project_management_issue_cross_referenced_weekly,
- :g_project_management_issue_moved_monthly, :g_project_management_issue_moved_weekly,
- :g_project_management_issue_related_monthly, :g_project_management_issue_related_weekly,
- :g_project_management_issue_unrelated_monthly, :g_project_management_issue_unrelated_weekly,
- :g_project_management_issue_marked_as_duplicate_monthly, :g_project_management_issue_marked_as_duplicate_weekly,
- :g_project_management_issue_locked_monthly, :g_project_management_issue_locked_weekly,
- :g_project_management_issue_unlocked_monthly, :g_project_management_issue_unlocked_weekly,
- :g_project_management_issue_designs_added_monthly, :g_project_management_issue_designs_added_weekly,
- :g_project_management_issue_designs_modified_monthly, :g_project_management_issue_designs_modified_weekly,
- :g_project_management_issue_designs_removed_monthly, :g_project_management_issue_designs_removed_weekly,
- :g_project_management_issue_due_date_changed_monthly, :g_project_management_issue_due_date_changed_weekly,
- :g_project_management_issue_time_estimate_changed_monthly, :g_project_management_issue_time_estimate_changed_weekly,
- :g_project_management_issue_time_spent_changed_monthly, :g_project_management_issue_time_spent_changed_weekly,
- :g_project_management_issue_comment_added_monthly, :g_project_management_issue_comment_added_weekly,
- :g_project_management_issue_comment_edited_monthly, :g_project_management_issue_comment_edited_weekly,
- :g_project_management_issue_comment_removed_monthly, :g_project_management_issue_comment_removed_weekly,
- :g_project_management_issue_cloned_monthly, :g_project_management_issue_cloned_weekly,
- :issues_edit_total_unique_counts_monthly, :issues_edit_total_unique_counts_weekly
- )
+ it 'is included in the Usage Ping hash structure' do
+ expect(metric_files_key_paths).to match_array(usage_ping_key_paths)
+ end
end
it 'includes counts keys' do
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index 86121b984ac..b216d3698b5 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -1080,7 +1080,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
end
it 'reports collected data categories' do
- expected_value = %w[Standard Subscription Operational Optional]
+ expected_value = %w[standard subscription operational optional]
allow_next_instance_of(ServicePing::PermitDataCategoriesService) do |instance|
expect(instance).to receive(:execute).and_return(expected_value)
diff --git a/spec/migrations/schedule_copy_ci_builds_columns_to_security_scans_spec.rb b/spec/migrations/schedule_copy_ci_builds_columns_to_security_scans_spec.rb
new file mode 100644
index 00000000000..5ebd8753892
--- /dev/null
+++ b/spec/migrations/schedule_copy_ci_builds_columns_to_security_scans_spec.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe ScheduleCopyCiBuildsColumnsToSecurityScans do
+ let_it_be(:namespaces) { table(:namespaces) }
+ let_it_be(:projects) { table(:projects) }
+ let_it_be(:ci_pipelines) { table(:ci_pipelines) }
+ let_it_be(:ci_builds) { table(:ci_builds) }
+ let_it_be(:security_scans) { table(:security_scans) }
+
+ let!(:namespace) { namespaces.create!(name: 'namespace', path: 'namespace') }
+ let!(:project) { projects.create!(namespace_id: namespace.id) }
+ let!(:pipeline) { ci_pipelines.create!(status: "success")}
+
+ let!(:build1) { ci_builds.create!(commit_id: pipeline.id, type: 'Ci::Build', project_id: project.id) }
+ let!(:build2) { ci_builds.create!(commit_id: pipeline.id, type: 'Ci::Build', project_id: project.id) }
+ let!(:build3) { ci_builds.create!(commit_id: pipeline.id, type: 'Ci::Build', project_id: project.id) }
+
+ let!(:scan1) { security_scans.create!(build_id: build1.id, scan_type: 1) }
+ let!(:scan2) { security_scans.create!(build_id: build2.id, scan_type: 1) }
+ let!(:scan3) { security_scans.create!(build_id: build3.id, scan_type: 1) }
+
+ before do
+ stub_const("#{described_class}::BATCH_SIZE", 2)
+ allow_next_instance_of(Gitlab::BackgroundMigration::CopyCiBuildsColumnsToSecurityScans) do |instance|
+ allow(instance).to receive(:mark_job_as_succeeded)
+ end
+ end
+
+ around do |example|
+ freeze_time { Sidekiq::Testing.fake! { example.run } }
+ end
+
+ it 'schedules background migrations', :aggregate_failures do
+ migrate!
+
+ expect(BackgroundMigrationWorker.jobs.size).to eq(2)
+ expect(described_class::MIGRATION).to be_scheduled_delayed_migration(2.minutes, scan1.id, scan2.id)
+ expect(described_class::MIGRATION).to be_scheduled_delayed_migration(4.minutes, scan3.id, scan3.id)
+ end
+end
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 26d2a05c54f..8e28b7dd250 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -796,17 +796,47 @@ RSpec.describe Issue do
end
end
+ shared_examples 'hidden issue readable by user' do
+ before do
+ issue.author.ban!
+ end
+
+ specify do
+ is_expected.to eq(true)
+ end
+
+ after do
+ issue.author.activate!
+ end
+ end
+
+ shared_examples 'hidden issue not readable by user' do
+ before do
+ issue.author.ban!
+ end
+
+ specify do
+ is_expected.to eq(false)
+ end
+
+ after do
+ issue.author.activate!
+ end
+ end
+
context 'with an admin user' do
let(:user) { build(:admin) }
context 'when admin mode is enabled', :enable_admin_mode do
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue readable by user'
+ it_behaves_like 'hidden issue readable by user'
end
context 'when admin mode is disabled' do
it_behaves_like 'issue not readable by user'
it_behaves_like 'confidential issue not readable by user'
+ it_behaves_like 'hidden issue not readable by user'
end
end
@@ -817,6 +847,7 @@ RSpec.describe Issue do
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue readable by user'
+ it_behaves_like 'hidden issue not readable by user'
end
context 'with a reporter user' do
@@ -826,6 +857,7 @@ RSpec.describe Issue do
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue readable by user'
+ it_behaves_like 'hidden issue not readable by user'
end
context 'with a guest user' do
@@ -835,6 +867,7 @@ RSpec.describe Issue do
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue not readable by user'
+ it_behaves_like 'hidden issue not readable by user'
context 'when user is an assignee' do
before do
@@ -843,6 +876,7 @@ RSpec.describe Issue do
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue readable by user'
+ it_behaves_like 'hidden issue not readable by user'
end
context 'when user is the author' do
@@ -852,6 +886,7 @@ RSpec.describe Issue do
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue readable by user'
+ it_behaves_like 'hidden issue not readable by user'
end
end
@@ -861,6 +896,7 @@ RSpec.describe Issue do
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue not readable by user'
+ it_behaves_like 'hidden issue not readable by user'
end
context 'using an internal project' do
@@ -873,6 +909,7 @@ RSpec.describe Issue do
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue not readable by user'
+ it_behaves_like 'hidden issue not readable by user'
end
context 'using an external user' do
@@ -882,6 +919,7 @@ RSpec.describe Issue do
it_behaves_like 'issue not readable by user'
it_behaves_like 'confidential issue not readable by user'
+ it_behaves_like 'hidden issue not readable by user'
end
end
@@ -892,6 +930,7 @@ RSpec.describe Issue do
it_behaves_like 'issue not readable by user'
it_behaves_like 'confidential issue not readable by user'
+ it_behaves_like 'hidden issue not readable by user'
end
end
@@ -1160,6 +1199,26 @@ RSpec.describe Issue do
end
end
+ describe '.without_hidden' do
+ let_it_be(:banned_user) { create(:user, :banned) }
+ let_it_be(:public_issue) { create(:issue, project: reusable_project) }
+ let_it_be(:hidden_issue) { create(:issue, project: reusable_project, author: banned_user) }
+
+ it 'only returns without_hidden issues' do
+ expect(described_class.without_hidden).to eq([public_issue])
+ end
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ban_user_feature_flag: false)
+ end
+
+ it 'returns public and hidden issues' do
+ expect(described_class.without_hidden).to eq([public_issue, hidden_issue])
+ end
+ end
+ end
+
describe '.by_project_id_and_iid' do
let_it_be(:issue_a) { create(:issue, project: reusable_project) }
let_it_be(:issue_b) { create(:issue, iid: issue_a.iid) }
diff --git a/spec/policies/issue_policy_spec.rb b/spec/policies/issue_policy_spec.rb
index 8ff936d5a35..d62271eedf6 100644
--- a/spec/policies/issue_policy_spec.rb
+++ b/spec/policies/issue_policy_spec.rb
@@ -360,6 +360,21 @@ RSpec.describe IssuePolicy do
expect(permissions(assignee, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata)
end
end
+
+ context 'with a hidden issue' do
+ let(:user) { create(:user) }
+ let(:banned_user) { create(:user, :banned) }
+ let(:admin) { create(:user, :admin)}
+ let(:hidden_issue) { create(:issue, project: project, author: banned_user) }
+
+ it 'does not allow non-admin user to read the issue' do
+ expect(permissions(user, hidden_issue)).not_to be_allowed(:read_issue)
+ end
+
+ it 'allows admin to read the issue', :enable_admin_mode do
+ expect(permissions(admin, hidden_issue)).to be_allowed(:read_issue)
+ end
+ end
end
context 'with external authorization enabled' do
diff --git a/spec/services/service_ping/permit_data_categories_service_spec.rb b/spec/services/service_ping/permit_data_categories_service_spec.rb
index 5b25f216c4d..550c0ea5e13 100644
--- a/spec/services/service_ping/permit_data_categories_service_spec.rb
+++ b/spec/services/service_ping/permit_data_categories_service_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe ServicePing::PermitDataCategoriesService do
end
it 'returns all categories' do
- expect(permitted_categories).to match_array(%w[Standard Subscription Operational Optional])
+ expect(permitted_categories).to match_array(%w[standard subscription operational optional])
end
end
diff --git a/spec/support/shared_contexts/services/service_ping/stubbed_service_ping_metrics_definitions_shared_context.rb b/spec/support/shared_contexts/services/service_ping/stubbed_service_ping_metrics_definitions_shared_context.rb
index ea72398010c..6b49a415889 100644
--- a/spec/support/shared_contexts/services/service_ping/stubbed_service_ping_metrics_definitions_shared_context.rb
+++ b/spec/support/shared_contexts/services/service_ping/stubbed_service_ping_metrics_definitions_shared_context.rb
@@ -6,20 +6,20 @@ RSpec.shared_context 'stubbed service ping metrics definitions' do
let(:metrics_definitions) { standard_metrics + subscription_metrics + operational_metrics + optional_metrics }
let(:standard_metrics) do
[
- metric_attributes('uuid', "Standard")
+ metric_attributes('uuid', "standard")
]
end
let(:operational_metrics) do
[
- metric_attributes('counts.merge_requests', "Operational"),
- metric_attributes('counts.todos', "Operational")
+ metric_attributes('counts.merge_requests', "operational"),
+ metric_attributes('counts.todos', "operational")
]
end
let(:optional_metrics) do
[
- metric_attributes('counts.boards', "Optional"),
+ metric_attributes('counts.boards', "optional"),
metric_attributes('gitaly.filesystems', '').except('data_category')
]
end