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>2023-12-15 03:12:58 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-12-15 03:12:58 +0300
commit45465a1f217b65ee3b11870175f363afaf912eb9 (patch)
tree0f4103ad51619ed03fc47cc28e32df3fb57b5c0c /spec
parent046498496e140f96beb63ff45ec9b0bb9acdbdd3 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/projects/merge_requests/diffs_controller_spec.rb18
-rw-r--r--spec/frontend/diffs/components/diff_file_spec.js21
-rw-r--r--spec/frontend/emoji/components/emoji_group_spec.js15
-rw-r--r--spec/lib/generators/gitlab/analytics/internal_events_generator_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb75
-rw-r--r--spec/lib/gitlab/git/diff_collection_spec.rb26
-rw-r--r--spec/lib/gitlab/git/diff_spec.rb25
-rw-r--r--spec/lib/gitlab/github_import/representation/representable_spec.rb43
-rw-r--r--spec/lib/gitlab/hook_data/project_builder_spec.rb120
-rw-r--r--spec/lib/gitlab/usage/metric_definition_spec.rb71
-rw-r--r--spec/models/ci/catalog/resource_spec.rb76
-rw-r--r--spec/models/concerns/disables_sti_spec.rb50
-rw-r--r--spec/models/every_model_spec.rb15
-rw-r--r--spec/models/group_spec.rb3
-rw-r--r--spec/models/project_authorization_spec.rb17
-rw-r--r--spec/requests/api/graphql/ci/catalog/resources_spec.rb2
-rw-r--r--spec/support/rspec_order_todo.yml2
-rw-r--r--spec/support/shared_contexts/services/service_ping/stubbed_service_ping_metrics_definitions_shared_context.rb3
-rw-r--r--spec/support/shared_examples/models/disable_sti_shared_examples.rb28
-rw-r--r--spec/tooling/lib/tooling/predictive_tests_spec.rb3
-rw-r--r--spec/views/layouts/header/_gitlab_version.html.haml_spec.rb36
-rw-r--r--spec/views/layouts/header/_new_dropdown.haml_spec.rb204
22 files changed, 481 insertions, 374 deletions
diff --git a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
index 80c68d3e091..b2b591d7929 100644
--- a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
@@ -657,5 +657,23 @@ RSpec.describe Projects::MergeRequests::DiffsController, feature_category: :code
end
end
end
+
+ context 'when collapse_generated_diff_files FF is enabled' do
+ it 'sets generated' do
+ go
+ expect(json_response["diff_files"][0]["viewer"]["generated"]).to eq(false)
+ end
+ end
+
+ context 'when collapse_generated_diff_files FF is disabled' do
+ before do
+ stub_feature_flags(collapse_generated_diff_files: false)
+ end
+
+ it 'sets generated as nil' do
+ go
+ expect(json_response["diff_files"][0]["viewer"]["generated"]).to be_nil
+ end
+ end
end
end
diff --git a/spec/frontend/diffs/components/diff_file_spec.js b/spec/frontend/diffs/components/diff_file_spec.js
index 90c42e6e5db..a9fbf4632ac 100644
--- a/spec/frontend/diffs/components/diff_file_spec.js
+++ b/spec/frontend/diffs/components/diff_file_spec.js
@@ -399,6 +399,27 @@ describe('DiffFile', () => {
});
});
+ describe('automatically collapsed generated file', () => {
+ beforeEach(() => {
+ makeFileAutomaticallyCollapsed(store);
+ const file = store.state.diffs.diffFiles[0];
+ Object.assign(store.state.diffs.diffFiles[0], {
+ ...file,
+ viewer: {
+ ...file.viewer,
+ generated: true,
+ },
+ });
+ });
+
+ it('should show the generated file warning with expansion button', () => {
+ expect(findDiffContentArea(wrapper).html()).toContain(
+ 'Generated files are collapsed by default. This behavior can be overriden via .gitattributes file if required.',
+ );
+ expect(findToggleButton(wrapper).exists()).toBe(true);
+ });
+ });
+
describe('not collapsed', () => {
beforeEach(() => {
makeFileOpenByDefault(store);
diff --git a/spec/frontend/emoji/components/emoji_group_spec.js b/spec/frontend/emoji/components/emoji_group_spec.js
index 75397ce25ff..a2a46bedd7b 100644
--- a/spec/frontend/emoji/components/emoji_group_spec.js
+++ b/spec/frontend/emoji/components/emoji_group_spec.js
@@ -1,5 +1,6 @@
import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
+import { GlButton } from '@gitlab/ui';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import EmojiGroup from '~/emoji/components/emoji_group.vue';
@@ -10,6 +11,9 @@ function factory(propsData = {}) {
wrapper = extendedWrapper(
shallowMount(EmojiGroup, {
propsData,
+ stubs: {
+ GlButton,
+ },
}),
);
}
@@ -19,7 +23,6 @@ describe('Emoji group component', () => {
factory({
emojis: [],
renderGroup: false,
- clickEmoji: jest.fn(),
});
expect(wrapper.findByTestId('emoji-button').exists()).toBe(false);
@@ -29,24 +32,20 @@ describe('Emoji group component', () => {
factory({
emojis: ['thumbsup', 'thumbsdown'],
renderGroup: true,
- clickEmoji: jest.fn(),
});
expect(wrapper.findAllByTestId('emoji-button').exists()).toBe(true);
expect(wrapper.findAllByTestId('emoji-button').length).toBe(2);
});
- it('calls clickEmoji', () => {
- const clickEmoji = jest.fn();
-
+ it('emits emoji-click', () => {
factory({
emojis: ['thumbsup', 'thumbsdown'],
renderGroup: true,
- clickEmoji,
});
- wrapper.findByTestId('emoji-button').trigger('click');
+ wrapper.findComponent(GlButton).vm.$emit('click');
- expect(clickEmoji).toHaveBeenCalledWith('thumbsup');
+ expect(wrapper.emitted('emoji-click')).toStrictEqual([['thumbsup']]);
});
});
diff --git a/spec/lib/generators/gitlab/analytics/internal_events_generator_spec.rb b/spec/lib/generators/gitlab/analytics/internal_events_generator_spec.rb
index 520a56db713..2d9356ca96d 100644
--- a/spec/lib/generators/gitlab/analytics/internal_events_generator_spec.rb
+++ b/spec/lib/generators/gitlab/analytics/internal_events_generator_spec.rb
@@ -175,7 +175,6 @@ RSpec.describe Gitlab::Analytics::InternalEventsGenerator, :silence_stdout, feat
metric_definition = base_metric_definition.merge(
"key_path" => key_path,
"time_frame" => time_frame,
- "instrumentation_class" => "RedisHLLMetric",
"events" => [{ "name" => event, "unique" => unique }]
).merge(metric_definition_extra)
expect(YAML.safe_load(File.read(metric_definition_path))).to eq(metric_definition)
@@ -193,7 +192,6 @@ RSpec.describe Gitlab::Analytics::InternalEventsGenerator, :silence_stdout, feat
metric_definition = base_metric_definition.merge(
"key_path" => key_path,
"time_frame" => time_frame,
- "instrumentation_class" => "TotalCountMetric",
"events" => [{ "name" => event }]
).merge(metric_definition_extra)
expect(YAML.safe_load(File.read(metric_definition_path))).to eq(metric_definition)
diff --git a/spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb b/spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb
index eb98c1cc7e6..f8d67a6f0b4 100644
--- a/spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb
+++ b/spec/lib/gitlab/ci/variables/builder/pipeline_spec.rb
@@ -66,6 +66,7 @@ RSpec.describe Gitlab::Ci::Variables::Builder::Pipeline, feature_category: :secr
let_it_be(:assignees) { create_list(:user, 2) }
let_it_be(:milestone) { create(:milestone, project: project) }
let_it_be(:labels) { create_list(:label, 2) }
+ let(:merge_request_description) { nil }
let(:merge_request) do
create(:merge_request, :simple,
@@ -73,6 +74,7 @@ RSpec.describe Gitlab::Ci::Variables::Builder::Pipeline, feature_category: :secr
target_project: project,
assignees: assignees,
milestone: milestone,
+ description: merge_request_description,
labels: labels)
end
@@ -114,6 +116,7 @@ RSpec.describe Gitlab::Ci::Variables::Builder::Pipeline, feature_category: :secr
).to_s,
'CI_MERGE_REQUEST_TITLE' => merge_request.title,
'CI_MERGE_REQUEST_DESCRIPTION' => merge_request.description,
+ 'CI_MERGE_REQUEST_DESCRIPTION_IS_TRUNCATED' => 'false',
'CI_MERGE_REQUEST_ASSIGNEES' => merge_request.assignee_username_list,
'CI_MERGE_REQUEST_MILESTONE' => milestone.title,
'CI_MERGE_REQUEST_LABELS' => labels.map(&:title).sort.join(','),
@@ -122,6 +125,78 @@ RSpec.describe Gitlab::Ci::Variables::Builder::Pipeline, feature_category: :secr
'CI_MERGE_REQUEST_SQUASH_ON_MERGE' => merge_request.squash_on_merge?.to_s
end
+ context 'when merge request description hits the limit' do
+ let(:merge_request_description) { 'a' * (MergeRequest::CI_MERGE_REQUEST_DESCRIPTION_MAX_LENGTH + 1) }
+
+ it 'truncates the exposed description' do
+ truncated_description = merge_request.description.truncate(
+ MergeRequest::CI_MERGE_REQUEST_DESCRIPTION_MAX_LENGTH
+ )
+ expect(subject.to_hash)
+ .to include(
+ 'CI_MERGE_REQUEST_DESCRIPTION' => truncated_description,
+ 'CI_MERGE_REQUEST_DESCRIPTION_IS_TRUNCATED' => 'true'
+ )
+ end
+ end
+
+ context 'when merge request description fits the length limit' do
+ let(:merge_request_description) { 'a' * (MergeRequest::CI_MERGE_REQUEST_DESCRIPTION_MAX_LENGTH - 1) }
+
+ it 'does not truncate the exposed description' do
+ expect(subject.to_hash)
+ .to include(
+ 'CI_MERGE_REQUEST_DESCRIPTION' => merge_request.description,
+ 'CI_MERGE_REQUEST_DESCRIPTION_IS_TRUNCATED' => 'false'
+ )
+ end
+ end
+
+ context 'when truncate_ci_merge_request_description feature flag is disabled' do
+ before do
+ stub_feature_flags(truncate_ci_merge_request_description: false)
+ end
+
+ context 'when merge request description hits the limit' do
+ let(:merge_request_description) { 'a' * (MergeRequest::CI_MERGE_REQUEST_DESCRIPTION_MAX_LENGTH + 1) }
+
+ it 'does not truncate the exposed description' do
+ expect(subject.to_hash)
+ .to include(
+ 'CI_MERGE_REQUEST_DESCRIPTION' => merge_request.description
+ )
+ expect(subject.to_hash)
+ .not_to have_key('CI_MERGE_REQUEST_DESCRIPTION_IS_TRUNCATED')
+ end
+ end
+
+ context 'when merge request description fits the length limit' do
+ let(:merge_request_description) { 'a' * (MergeRequest::CI_MERGE_REQUEST_DESCRIPTION_MAX_LENGTH - 1) }
+
+ it 'does not truncate the exposed description' do
+ expect(subject.to_hash)
+ .to include(
+ 'CI_MERGE_REQUEST_DESCRIPTION' => merge_request.description
+ )
+ expect(subject.to_hash)
+ .not_to have_key('CI_MERGE_REQUEST_DESCRIPTION_IS_TRUNCATED')
+ end
+ end
+
+ context 'when merge request description does not exist' do
+ let(:merge_request_description) { nil }
+
+ it 'does not truncate the exposed description' do
+ expect(subject.to_hash)
+ .to include(
+ 'CI_MERGE_REQUEST_DESCRIPTION' => merge_request.description
+ )
+ expect(subject.to_hash)
+ .not_to have_key('CI_MERGE_REQUEST_DESCRIPTION_IS_TRUNCATED')
+ end
+ end
+ end
+
it 'exposes diff variables' do
expect(subject.to_hash)
.to include(
diff --git a/spec/lib/gitlab/git/diff_collection_spec.rb b/spec/lib/gitlab/git/diff_collection_spec.rb
index 4ab4d047522..dc60d486f49 100644
--- a/spec/lib/gitlab/git/diff_collection_spec.rb
+++ b/spec/lib/gitlab/git/diff_collection_spec.rb
@@ -598,6 +598,32 @@ RSpec.describe Gitlab::Git::DiffCollection, feature_category: :source_code_manag
end
end
+ context 'with existing generated value in the hash' do
+ let(:collection) do
+ described_class.new([{ diff: 'some content', generated: true }], options)
+ end
+
+ context 'when collapse_generated on' do
+ let(:options) { { collapse_generated: true } }
+
+ it 'sets the diff as generated' do
+ collection.each do |diff|
+ expect(diff.generated).to eq true
+ end
+ end
+ end
+
+ context 'when collapse_generated off' do
+ let(:options) { { collapse_generated: false } }
+
+ it 'does not set the diff as generated' do
+ collection.each do |diff|
+ expect(diff.generated).to be_nil
+ end
+ end
+ end
+ end
+
context 'when diff are too large' do
let(:collection) do
described_class.new([{ diff: 'a' * 204800 }])
diff --git a/spec/lib/gitlab/git/diff_spec.rb b/spec/lib/gitlab/git/diff_spec.rb
index 2fca81299e0..c40445433c0 100644
--- a/spec/lib/gitlab/git/diff_spec.rb
+++ b/spec/lib/gitlab/git/diff_spec.rb
@@ -156,6 +156,31 @@ EOT
expect(diff).to be_collapsed
end
end
+
+ context 'when the file is set as generated' do
+ let(:diff) { described_class.new(gitaly_diff, generated: true, expanded: expanded) }
+ let(:raw_patch) { 'some text' }
+
+ context 'when expanded is set to false' do
+ let(:expanded) { false }
+
+ it 'will be marked as generated and collapsed' do
+ expect(diff).to be_generated
+ expect(diff).to be_collapsed
+ expect(diff.diff).to be_empty
+ end
+ end
+
+ context 'when expanded is set to true' do
+ let(:expanded) { true }
+
+ it 'will still be marked as generated, but not as collapsed' do
+ expect(diff).to be_generated
+ expect(diff).not_to be_collapsed
+ expect(diff.diff).not_to be_empty
+ end
+ end
+ end
end
context 'using a Gitaly::CommitDelta' do
diff --git a/spec/lib/gitlab/github_import/representation/representable_spec.rb b/spec/lib/gitlab/github_import/representation/representable_spec.rb
new file mode 100644
index 00000000000..4bc495c40f5
--- /dev/null
+++ b/spec/lib/gitlab/github_import/representation/representable_spec.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::GithubImport::Representation::Representable, feature_category: :importers do
+ let(:representation_class) do
+ subject_module = described_class
+
+ Class.new do
+ include subject_module
+ end
+ end
+
+ let(:representable) { representation_class.new }
+
+ describe '#github_identifiers' do
+ subject(:github_identifiers) { representable.github_identifiers }
+
+ context 'when class does not define `#github_identifiers`' do
+ it 'tracks the error' do
+ error = NotImplementedError.new('Subclasses must implement #github_identifiers')
+
+ expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception).with(error)
+ is_expected.to eq({})
+ end
+ end
+
+ context 'when class defines `#github_identifiers`' do
+ let(:representation_class) do
+ Class.new(super()) do
+ def github_identifiers
+ { id: 1 }
+ end
+ end
+ end
+
+ it 'does not track an exception and returns the identifiers' do
+ expect(Gitlab::ErrorTracking).not_to receive(:track_and_raise_for_dev_exception)
+ is_expected.to eq({ id: 1 })
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/hook_data/project_builder_spec.rb b/spec/lib/gitlab/hook_data/project_builder_spec.rb
index f80faac563d..9d5eaf0608c 100644
--- a/spec/lib/gitlab/hook_data/project_builder_spec.rb
+++ b/spec/lib/gitlab/hook_data/project_builder_spec.rb
@@ -4,8 +4,8 @@ require 'spec_helper'
RSpec.describe Gitlab::HookData::ProjectBuilder do
let_it_be(:user) { create(:user, name: 'John', email: 'john@example.com') }
- let_it_be(:namespace) { create(:namespace, owner: user) }
- let_it_be(:project) { create(:project, :internal, name: 'my_project', namespace: namespace) }
+ let_it_be(:user2) { create(:user, name: 'Peter') }
+ let_it_be(:user3_non_owner) { create(:user, name: 'Not_Owner') }
describe '#build' do
let(:data) { described_class.new(project).build(event) }
@@ -24,13 +24,13 @@ RSpec.describe Gitlab::HookData::ProjectBuilder do
expect(data[:created_at]).to eq(project.created_at.xmlschema)
expect(data[:updated_at]).to eq(project.updated_at.xmlschema)
- expect(data[:name]).to eq('my_project')
+ expect(data[:name]).to eq(project.name)
expect(data[:path]).to eq(project.path)
expect(data[:path_with_namespace]).to eq(project.full_path)
expect(data[:project_id]).to eq(project.id)
- expect(data[:owner_name]).to eq('John')
- expect(data[:owner_email]).to eq(_('[REDACTED]'))
- expect(data[:owners]).to contain_exactly({ name: 'John', email: _('[REDACTED]') })
+ expect(data[:owner_name]).to eq(owner_name)
+ expect(data[:owner_email]).to eq(owner_email)
+ expect(data[:owners]).to match_array(owners_data)
expect(data[:project_visibility]).to eq('internal')
end
end
@@ -48,40 +48,104 @@ RSpec.describe Gitlab::HookData::ProjectBuilder do
end
end
- context 'on create' do
- let(:event) { :create }
+ context 'the project is created in a personal namespace' do
+ let(:owner_name) { user.name }
+ let(:owner_email) { _('[REDACTED]') }
+ let(:owners_data) { [{ name: 'John', email: _('[REDACTED]') }, { name: 'Peter', email: _('[REDACTED]') }] }
+ let_it_be(:namespace) { create(:namespace, owner: user) }
+ let_it_be(:project) { create(:project, :internal, name: 'personal project', namespace: namespace) }
- it { expect(event_name).to eq('project_create') }
+ before_all do
+ project.add_owner(user2)
+ project.add_maintainer(user3_non_owner)
+ end
- it_behaves_like 'includes the required attributes'
- it_behaves_like 'does not include `old_path_with_namespace` attribute'
- end
+ context 'on create' do
+ let(:event) { :create }
- context 'on destroy' do
- let(:event) { :destroy }
+ it { expect(event_name).to eq('project_create') }
- it { expect(event_name).to eq('project_destroy') }
+ it_behaves_like 'includes the required attributes'
+ it_behaves_like 'does not include `old_path_with_namespace` attribute'
+ end
- it_behaves_like 'includes the required attributes'
- it_behaves_like 'does not include `old_path_with_namespace` attribute'
- end
+ context 'on destroy' do
+ let(:event) { :destroy }
+
+ it { expect(event_name).to eq('project_destroy') }
+
+ it_behaves_like 'includes the required attributes'
+ it_behaves_like 'does not include `old_path_with_namespace` attribute'
+ end
- context 'on rename' do
- let(:event) { :rename }
+ context 'on rename' do
+ let(:event) { :rename }
- it { expect(event_name).to eq('project_rename') }
+ it { expect(event_name).to eq('project_rename') }
- it_behaves_like 'includes the required attributes'
- it_behaves_like 'includes `old_path_with_namespace` attribute'
+ it_behaves_like 'includes the required attributes'
+ it_behaves_like 'includes `old_path_with_namespace` attribute'
+ end
+
+ context 'on transfer' do
+ let(:event) { :transfer }
+
+ it { expect(event_name).to eq('project_transfer') }
+
+ it_behaves_like 'includes the required attributes'
+ it_behaves_like 'includes `old_path_with_namespace` attribute'
+ end
end
- context 'on transfer' do
- let(:event) { :transfer }
+ context 'the project is created in a group' do
+ let(:owner_name) { group.name }
+ let(:owner_email) { "" }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, :internal, name: 'group project', namespace: group) }
+ let(:owners_data) { [{ name: 'John', email: _('[REDACTED]') }, { email: "[REDACTED]", name: "Peter" }] }
+
+ before_all do
+ group.add_owner(user)
+ group.add_owner(user2)
+ group.add_maintainer(user3_non_owner)
+ end
+
+ # Repeat the tests in the previous context
+ context 'on create' do
+ let(:event) { :create }
- it { expect(event_name).to eq('project_transfer') }
+ it { expect(event_name).to eq('project_create') }
- it_behaves_like 'includes the required attributes'
- it_behaves_like 'includes `old_path_with_namespace` attribute'
+ it_behaves_like 'includes the required attributes'
+ it_behaves_like 'does not include `old_path_with_namespace` attribute'
+ end
+
+ context 'on destroy' do
+ let(:event) { :destroy }
+
+ it { expect(event_name).to eq('project_destroy') }
+
+ it_behaves_like 'includes the required attributes'
+ it_behaves_like 'does not include `old_path_with_namespace` attribute'
+ end
+
+ context 'on rename' do
+ let(:event) { :rename }
+
+ it { expect(event_name).to eq('project_rename') }
+
+ it_behaves_like 'includes the required attributes'
+ it_behaves_like 'includes `old_path_with_namespace` attribute'
+ end
+
+ context 'on transfer' do
+ let(:event) { :transfer }
+
+ it { expect(event_name).to eq('project_transfer') }
+
+ it_behaves_like 'includes the required attributes'
+ it_behaves_like 'includes `old_path_with_namespace` attribute'
+ end
end
end
end
diff --git a/spec/lib/gitlab/usage/metric_definition_spec.rb b/spec/lib/gitlab/usage/metric_definition_spec.rb
index 08adc031631..fb46d48c1bb 100644
--- a/spec/lib/gitlab/usage/metric_definition_spec.rb
+++ b/spec/lib/gitlab/usage/metric_definition_spec.rb
@@ -46,6 +46,34 @@ RSpec.describe Gitlab::Usage::MetricDefinition, feature_category: :service_ping
end
end
+ describe '.instrumentation_class' do
+ context 'for non internal events' do
+ let(:attributes) { { key_path: 'metric1', instrumentation_class: 'RedisHLLMetric', data_source: 'redis_hll' } }
+
+ it 'returns class from the definition' do
+ expect(definition.instrumentation_class).to eq('RedisHLLMetric')
+ end
+ end
+
+ context 'for internal events' do
+ context 'for total counter' do
+ let(:attributes) { { key_path: 'metric1', data_source: 'internal_events', events: [{ name: 'a' }] } }
+
+ it 'returns TotalCounterMetric' do
+ expect(definition.instrumentation_class).to eq('TotalCountMetric')
+ end
+ end
+
+ context 'for uniq counter' do
+ let(:attributes) { { key_path: 'metric1', data_source: 'internal_events', events: [{ name: 'a', unique: :id }] } }
+
+ it 'returns RedisHLLMetric' do
+ expect(definition.instrumentation_class).to eq('RedisHLLMetric')
+ end
+ end
+ end
+ end
+
describe 'not_removed' do
let(:all_definitions) do
metrics_definitions = [
@@ -71,12 +99,13 @@ RSpec.describe Gitlab::Usage::MetricDefinition, feature_category: :service_ping
describe '#with_instrumentation_class' do
let(:all_definitions) do
metrics_definitions = [
- { key_path: 'metric1', instrumentation_class: 'RedisHLLMetric', status: 'active' },
- { key_path: 'metric2', instrumentation_class: 'RedisHLLMetric', status: 'broken' },
- { key_path: 'metric3', instrumentation_class: 'RedisHLLMetric', status: 'active' },
- { key_path: 'metric4', instrumentation_class: 'RedisHLLMetric', status: 'removed' },
- { key_path: 'metric5', status: 'active' },
- { key_path: 'metric_missing_status' }
+ { key_path: 'metric1', status: 'active', data_source: 'redis_hll', instrumentation_class: 'RedisHLLMetric' },
+ { key_path: 'metric2', status: 'active', data_source: 'internal_events' }, # class is defined by data_source
+
+ { key_path: 'metric3', status: 'active', data_source: 'redis_hll' },
+ { key_path: 'metric4', status: 'removed', instrumentation_class: 'RedisHLLMetric', data_source: 'redis_hll' },
+ { key_path: 'metric5', status: 'removed', data_source: 'internal_events' },
+ { key_path: 'metric_missing_status', data_source: 'internal_events' }
]
metrics_definitions.map { |definition| described_class.new(definition[:key_path], definition.symbolize_keys) }
end
@@ -86,15 +115,7 @@ RSpec.describe Gitlab::Usage::MetricDefinition, feature_category: :service_ping
end
it 'includes definitions with instrumentation_class' do
- expect(described_class.with_instrumentation_class.count).to eq(3)
- end
-
- context 'with removed metric' do
- let(:metric_status) { 'removed' }
-
- it 'excludes removed definitions' do
- expect(described_class.with_instrumentation_class.count).to eq(3)
- end
+ expect(described_class.with_instrumentation_class.map(&:key_path)).to match_array(%w[metric1 metric2])
end
end
@@ -224,25 +245,9 @@ RSpec.describe Gitlab::Usage::MetricDefinition, feature_category: :service_ping
where(:instrumentation_class, :options, :events, :is_valid) do
'AnotherClass' | { events: ['a'] } | [{ name: 'a', unique: 'user.id' }] | false
- nil | { events: ['a'] } | [{ name: 'a', unique: 'user.id' }] | false
- 'RedisHLLMetric' | { events: ['a'] } | [{ name: 'a', unique: 'user.id' }] | true
+ 'RedisHLLMetric' | { events: ['a'] } | [{ name: 'a', unique: 'user.id' }] | false
'RedisHLLMetric' | { events: ['a'] } | nil | false
- 'RedisHLLMetric' | nil | [{ name: 'a', unique: 'user.id' }] | false
- 'RedisHLLMetric' | { events: ['a'] } | [{ name: 'a', unique: 'a' }] | false
- 'RedisHLLMetric' | { events: 'a' } | [{ name: 'a', unique: 'user.id' }] | false
- 'RedisHLLMetric' | { events: [2] } | [{ name: 'a', unique: 'user.id' }] | false
- 'RedisHLLMetric' | { events: ['a'], a: 'b' } | [{ name: 'a', unique: 'user.id' }] | false
- 'RedisHLLMetric' | { events: ['a'] } | [{ name: 'a', unique: 'user.id', b: 'c' }] | false
- 'RedisHLLMetric' | { events: ['a'] } | [{ name: 'a' }] | false
- 'RedisHLLMetric' | { events: ['a'] } | [{ unique: 'user.id' }] | false
- 'TotalCountMetric' | { events: ['a'] } | [{ name: 'a' }] | true
- 'TotalCountMetric' | { events: ['a'] } | [{ name: 'a', unique: 'user.id' }] | false
- 'TotalCountMetric' | { events: ['a'] } | nil | false
- 'TotalCountMetric' | nil | [{ name: 'a' }] | false
- 'TotalCountMetric' | { events: [2] } | [{ name: 'a' }] | false
- 'TotalCountMetric' | { events: ['a'] } | [{}] | false
- 'TotalCountMetric' | 'a' | [{ name: 'a' }] | false
- 'TotalCountMetric' | { events: ['a'], a: 'b' } | [{ name: 'a' }] | false
+ nil | { events: ['a'] } | [{ name: 'a', unique: 'user.id' }] | true
end
with_them do
diff --git a/spec/models/ci/catalog/resource_spec.rb b/spec/models/ci/catalog/resource_spec.rb
index 8ed7369e3d7..b597586e899 100644
--- a/spec/models/ci/catalog/resource_spec.rb
+++ b/spec/models/ci/catalog/resource_spec.rb
@@ -117,6 +117,82 @@ RSpec.describe Ci::Catalog::Resource, feature_category: :pipeline_composition do
end
end
+ describe 'authorized catalog resources' do
+ let_it_be(:namespace) { create(:group) }
+ let_it_be(:other_namespace) { create(:group) }
+ let_it_be(:other_user) { create(:user) }
+
+ let_it_be(:public_project) { create(:project, :public) }
+ let_it_be(:internal_project) { create(:project, :internal) }
+ let_it_be(:internal_namespace_project) { create(:project, :internal, namespace: namespace) }
+ let_it_be(:private_namespace_project) { create(:project, namespace: namespace) }
+ let_it_be(:other_private_namespace_project) { create(:project, namespace: other_namespace) }
+
+ let_it_be(:public_resource) { create(:ci_catalog_resource, project: public_project) }
+ let_it_be(:internal_resource) { create(:ci_catalog_resource, project: internal_project) }
+ let_it_be(:internal_namespace_resource) { create(:ci_catalog_resource, project: internal_namespace_project) }
+ let_it_be(:private_namespace_resource) { create(:ci_catalog_resource, project: private_namespace_project) }
+
+ let_it_be(:other_private_namespace_resource) do
+ create(:ci_catalog_resource, project: other_private_namespace_project)
+ end
+
+ before_all do
+ namespace.add_reporter(current_user)
+ other_namespace.add_guest(other_user)
+ end
+
+ describe '.public_or_visible_to_user' do
+ subject(:resources) { described_class.public_or_visible_to_user(current_user) }
+
+ it 'returns all resources visible to the user' do
+ expect(resources).to contain_exactly(
+ public_resource, internal_resource, internal_namespace_resource, private_namespace_resource)
+ end
+
+ context 'with a different user' do
+ let(:current_user) { other_user }
+
+ it 'returns all resources visible to the user' do
+ expect(resources).to contain_exactly(
+ public_resource, internal_resource, internal_namespace_resource, other_private_namespace_resource)
+ end
+ end
+
+ context 'when the user is nil' do
+ let(:current_user) { nil }
+
+ it 'returns only public resources' do
+ expect(resources).to contain_exactly(public_resource)
+ end
+ end
+ end
+
+ describe '.visible_to_user' do
+ subject(:resources) { described_class.visible_to_user(current_user) }
+
+ it "returns resources belonging to the user's authorized namespaces" do
+ expect(resources).to contain_exactly(internal_namespace_resource, private_namespace_resource)
+ end
+
+ context 'with a different user' do
+ let(:current_user) { other_user }
+
+ it "returns resources belonging to the user's authorized namespaces" do
+ expect(resources).to contain_exactly(other_private_namespace_resource)
+ end
+ end
+
+ context 'when the user is nil' do
+ let(:current_user) { nil }
+
+ it 'does not return any resources' do
+ expect(resources).to be_empty
+ end
+ end
+ end
+ end
+
describe '#state' do
it 'defaults to draft' do
expect(resource_a.state).to eq('draft')
diff --git a/spec/models/concerns/disables_sti_spec.rb b/spec/models/concerns/disables_sti_spec.rb
index 85b943c3563..07eea635289 100644
--- a/spec/models/concerns/disables_sti_spec.rb
+++ b/spec/models/concerns/disables_sti_spec.rb
@@ -3,53 +3,13 @@
require 'spec_helper'
RSpec.describe DisablesSti, feature_category: :shared do
- describe '#new' do
- context 'for a non STI class like Project' do
- it 'can initialize' do
- expect { Project.new }.not_to raise_error
- end
+ describe '.allow_legacy_sti_class' do
+ it 'is nil by default' do
+ expect(ApplicationRecord.allow_legacy_sti_class).to eq(nil)
end
- context 'for a base class which has an inheritance column' do
- it 'can initialize' do
- expect { Label.new }.not_to raise_error
- end
- end
-
- context 'for an STI class that previously existed' do
- it 'can initialize' do
- expect { GroupLabel.new }.not_to raise_error
- end
- end
-
- context 'for an STI class that is new' do
- before do
- stub_const('DummyModel', Class.new(Label))
- end
-
- it 'cannot initialize' do
- expect { DummyModel.new }.to raise_error(/Do not use Single Table Inheritance/)
- end
-
- context 'when SKIP_STI_CHECK is true' do
- before do
- stub_const("#{described_class}::SKIP_STI_CHECK", 'true')
- end
-
- it 'can initialize' do
- expect { DummyModel.new }.not_to raise_error
- end
- end
- end
-
- context 'for an STI class descending from Integration' do
- before do
- stub_const('IntegrationDummyModel', Class.new(Integration))
- end
-
- it 'can initialize' do
- expect { IntegrationDummyModel.new }.not_to raise_error
- end
+ it 'is true on legacy models' do
+ expect(PersonalSnippet.allow_legacy_sti_class).to eq(true)
end
end
end
diff --git a/spec/models/every_model_spec.rb b/spec/models/every_model_spec.rb
index b1ed4e6c145..479fc8d3dfa 100644
--- a/spec/models/every_model_spec.rb
+++ b/spec/models/every_model_spec.rb
@@ -2,19 +2,10 @@
require 'spec_helper'
-RSpec.describe "Every model", feature_category: :shared do
+RSpec.describe 'Every model', feature_category: :shared do
describe 'disallows STI', :eager_load do
- let(:models) { ApplicationRecord.descendants.reject(&:abstract_class?) }
-
- it 'does not allow STI', :aggregate_failures do
- models.each do |model|
- next if model == model.base_class
- next if model.allow_legacy_sti_class
-
- expect(model).not_to have_attribute(model.inheritance_column),
- "Do not use Single Table Inheritance (`#{model.name}` inherits `#{model.base_class.name}`). " \
- "See https://docs.gitlab.com/ee/development/database/single_table_inheritance.html"
- end
+ include_examples 'Model disables STI' do
+ let(:models) { ApplicationRecord.descendants.reject(&:abstract_class?) }
end
end
end
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index bff2ec641f3..891d251c7e2 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -11,10 +11,11 @@ RSpec.describe Group, feature_category: :groups_and_projects do
describe 'associations' do
it { is_expected.to have_many :projects }
it { is_expected.to have_many(:all_group_members).dependent(:destroy) }
+ it { is_expected.to have_many(:all_owner_members) }
it { is_expected.to have_many(:group_members).dependent(:destroy) }
it { is_expected.to have_many(:namespace_members) }
it { is_expected.to have_many(:users).through(:group_members) }
- it { is_expected.to have_many(:owners).through(:all_group_members) }
+ it { is_expected.to have_many(:owners).through(:all_owner_members) }
it { is_expected.to have_many(:requesters).dependent(:destroy) }
it { is_expected.to have_many(:namespace_requesters) }
it { is_expected.to have_many(:members_and_requesters) }
diff --git a/spec/models/project_authorization_spec.rb b/spec/models/project_authorization_spec.rb
index 64ad25f559d..00376e1a871 100644
--- a/spec/models/project_authorization_spec.rb
+++ b/spec/models/project_authorization_spec.rb
@@ -110,6 +110,23 @@ RSpec.describe ProjectAuthorization, feature_category: :groups_and_projects do
end
end
+ describe '.owners' do
+ let_it_be(:project_original_owner_authorization) { project.owner.project_authorizations.first }
+ let_it_be(:project_authorization_owner) { create(:project_authorization, :owner, project: project) }
+
+ before_all do
+ create(:project_authorization, :guest, project: project)
+ create(:project_authorization, :developer, project: project)
+ end
+
+ it 'returns all records which only have Owners access' do
+ expect(described_class.owners.map(&:attributes)).to match_array([
+ project_original_owner_authorization,
+ project_authorization_owner
+ ].map(&:attributes))
+ end
+ end
+
describe '.for_project' do
let_it_be(:project_2) { create(:project, namespace: user.namespace) }
let_it_be(:project_3) { create(:project, namespace: user.namespace) }
diff --git a/spec/requests/api/graphql/ci/catalog/resources_spec.rb b/spec/requests/api/graphql/ci/catalog/resources_spec.rb
index 23d91f6dd76..49a3f3be1d7 100644
--- a/spec/requests/api/graphql/ci/catalog/resources_spec.rb
+++ b/spec/requests/api/graphql/ci/catalog/resources_spec.rb
@@ -60,7 +60,7 @@ RSpec.describe 'Query.ciCatalogResources', feature_category: :pipeline_compositi
it do
ctx = { current_user: user }
- control_count = ActiveRecord::QueryRecorder.new do
+ control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do
run_with_clean_state(query, context: ctx)
end
diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml
index 55aaadce97c..5e19043639d 100644
--- a/spec/support/rspec_order_todo.yml
+++ b/spec/support/rspec_order_todo.yml
@@ -9328,8 +9328,6 @@
- './spec/views/layouts/devise.html.haml_spec.rb'
- './spec/views/layouts/_flash.html.haml_spec.rb'
- './spec/views/layouts/fullscreen.html.haml_spec.rb'
-- './spec/views/layouts/header/_gitlab_version.html.haml_spec.rb'
-- './spec/views/layouts/header/_new_dropdown.haml_spec.rb'
- './spec/views/layouts/_head.html.haml_spec.rb'
- './spec/views/layouts/profile.html.haml_spec.rb'
- './spec/views/layouts/_published_experiments.html.haml_spec.rb'
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 24f0d22da47..b51c68f4958 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
@@ -50,7 +50,8 @@ RSpec.shared_context 'stubbed service ping metrics definitions' do
'value_type' => value_type,
'status' => status,
'instrumentation_class' => instrumentation_class,
- 'time_frame' => 'all'
+ 'time_frame' => 'all',
+ 'data_source' => 'redis_hll'
}
end
end
diff --git a/spec/support/shared_examples/models/disable_sti_shared_examples.rb b/spec/support/shared_examples/models/disable_sti_shared_examples.rb
new file mode 100644
index 00000000000..090592827d1
--- /dev/null
+++ b/spec/support/shared_examples/models/disable_sti_shared_examples.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+# Checks whether STI is disabled in +models+.
+#
+# Parameter:
+# - models: List of model classes
+RSpec.shared_examples 'Model disables STI' do
+ skip_sti_check = Gitlab::Utils.to_boolean(ENV['SKIP_STI_CHECK'], default: false)
+
+ it 'does not allow STI', :aggregate_failures, unless: skip_sti_check do
+ models.each do |model|
+ next unless model
+ next unless model < ApplicationRecord
+ next if model == model.base_class
+ next if model.allow_legacy_sti_class
+
+ expect(model).not_to have_attribute(model.inheritance_column),
+ "Do not use Single Table Inheritance (`#{model.name}` inherits `#{model.base_class.name}`). " \
+ "See https://docs.gitlab.com/ee/development/database/single_table_inheritance.html"
+ end
+ end
+end
+
+RSpec.shared_examples 'STI disabled', type: :model do # rubocop:disable RSpec/SharedGroupsMetadata -- Shared example is run within every spec tagged `type: :model`
+ include_examples 'Model disables STI' do
+ let(:models) { [described_class] }
+ end
+end
diff --git a/spec/tooling/lib/tooling/predictive_tests_spec.rb b/spec/tooling/lib/tooling/predictive_tests_spec.rb
index fdb7d09a3e2..e49daa70295 100644
--- a/spec/tooling/lib/tooling/predictive_tests_spec.rb
+++ b/spec/tooling/lib/tooling/predictive_tests_spec.rb
@@ -106,6 +106,7 @@ RSpec.describe Tooling::PredictiveTests, feature_category: :tooling do
context 'when some files used for frontend fixtures were changed' do
let(:changed_files_content) { 'app/models/todo.rb' }
let(:changed_files_matching_test) { 'spec/models/todo_spec.rb' }
+ let(:additional_matching_tests) { 'spec/models/every_model_spec.rb' }
let(:matching_frontend_fixture) { 'tmp/tests/frontend/fixtures-ee/todos/todos.html' }
let(:fixtures_mapping_content) do
JSON.dump(changed_files_matching_test => [matching_frontend_fixture]) # rubocop:disable Gitlab/Json
@@ -120,7 +121,7 @@ RSpec.describe Tooling::PredictiveTests, feature_category: :tooling do
it 'appends the spec file to RSPEC_MATCHING_TESTS_PATH' do
expect { subject }.to change { File.read(matching_tests.path) }
.from(matching_tests_initial_content)
- .to("#{matching_tests_initial_content} #{changed_files_matching_test}")
+ .to("#{matching_tests_initial_content} #{additional_matching_tests} #{changed_files_matching_test}")
end
it 'does not change files other than RSPEC_CHANGED_FILES_PATH nor RSPEC_MATCHING_TESTS_PATH' do
diff --git a/spec/views/layouts/header/_gitlab_version.html.haml_spec.rb b/spec/views/layouts/header/_gitlab_version.html.haml_spec.rb
deleted file mode 100644
index a027bdd6357..00000000000
--- a/spec/views/layouts/header/_gitlab_version.html.haml_spec.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'layouts/header/_gitlab_version' do
- describe 'when show_version_check? is true' do
- before do
- allow(view).to receive(:show_version_check?).and_return(true)
- render
- end
-
- it 'renders the version check badge' do
- expect(rendered).to have_selector('.js-gitlab-version-check-badge')
- end
-
- it 'renders the container as a link' do
- expect(rendered).to have_selector(
- 'a[data-testid="gitlab-version-container"][href="/help/update/index"]'
- )
- end
-
- it 'renders the container with correct data-tracking attributes' do
- expect(rendered).to have_selector(
- 'a[data-testid="gitlab-version-container"][data-track-action="click_link"]'
- )
-
- expect(rendered).to have_selector(
- 'a[data-testid="gitlab-version-container"][data-track-label="version_help_dropdown"]'
- )
-
- expect(rendered).to have_selector(
- 'a[data-testid="gitlab-version-container"][data-track-property="navigation_top"]'
- )
- end
- end
-end
diff --git a/spec/views/layouts/header/_new_dropdown.haml_spec.rb b/spec/views/layouts/header/_new_dropdown.haml_spec.rb
deleted file mode 100644
index ef028da7ab9..00000000000
--- a/spec/views/layouts/header/_new_dropdown.haml_spec.rb
+++ /dev/null
@@ -1,204 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'layouts/header/_new_dropdown', feature_category: :navigation do
- let_it_be(:user) { create(:user) } # rubocop:disable RSpec/FactoryBot/AvoidCreate
-
- shared_examples_for 'invite member selector' do
- context 'with ability to invite members' do
- it { is_expected.to have_selector('.js-invite-members-trigger') }
- end
-
- context 'without ability to invite members' do
- let(:invite_member) { false }
-
- it { is_expected.not_to have_selector('.js-invite-members-trigger') }
- end
- end
-
- context 'with group-specific links' do
- let_it_be(:group) { create(:group) } # rubocop:disable RSpec/FactoryBot/AvoidCreate
-
- before do
- stub_current_user(user)
-
- assign(:group, group)
- end
-
- context 'as a Group owner' do
- before do
- group.add_owner(user)
- end
-
- it 'has a "New project" link' do
- render
-
- expect(rendered).to have_link('New project', href: new_project_path(namespace_id: group.id))
- end
-
- it 'has a "New subgroup" link' do
- render
-
- expect(rendered)
- .to have_link('New subgroup', href: new_group_path(parent_id: group.id, anchor: 'create-group-pane'))
- end
- end
-
- describe 'invite members item' do
- let(:href) { group_group_members_path(group) }
- let(:invite_member) { true }
-
- before do
- allow(view).to receive(:can?).with(user, :create_projects, group).and_return(true)
- allow(view).to receive(:can?).with(user, :admin_group_member, group).and_return(invite_member)
- allow(view).to receive(:can_admin_group_member?).and_return(invite_member)
- end
-
- subject do
- render
-
- rendered
- end
-
- it_behaves_like 'invite member selector'
- end
- end
-
- context 'with project-specific links' do
- let_it_be(:project) { create(:project, creator: user, namespace: user.namespace) } # rubocop:disable RSpec/FactoryBot/AvoidCreate
-
- before do
- assign(:project, project)
- end
-
- context 'as a Project owner' do
- before do
- stub_current_user(user)
- end
-
- it 'has a "New issue" link' do
- render
-
- expect(rendered).to have_link('New issue', href: new_project_issue_path(project))
- end
-
- it 'has a "New merge request" link' do
- render
-
- expect(rendered).to have_link('New merge request', href: project_new_merge_request_path(project))
- end
-
- it 'has a "New snippet" link' do
- render
-
- expect(rendered).to have_link('New snippet', href: new_project_snippet_path(project))
- end
- end
-
- context 'as a Project guest' do
- let_it_be(:guest) { create(:user) } # rubocop:disable RSpec/FactoryBot/AvoidCreate
-
- before do
- stub_current_user(guest)
- project.add_guest(guest)
- end
-
- it 'has no "New merge request" link' do
- render
-
- expect(rendered).not_to have_link('New merge request')
- end
-
- it 'has no "New snippet" link' do
- render
-
- expect(rendered).not_to have_link('New snippet', href: new_project_snippet_path(project))
- end
- end
-
- describe 'invite members item' do
- let(:invite_member) { true }
- let(:href) { project_project_members_path(project) }
-
- before do
- allow(view).to receive(:can_admin_project_member?).and_return(invite_member)
- stub_current_user(user)
- end
-
- subject do
- render
-
- rendered
- end
-
- it_behaves_like 'invite member selector'
- end
- end
-
- context 'with global links' do
- before do
- stub_current_user(user)
- end
-
- it 'has a "New project" link' do
- render
-
- expect(rendered).to have_link('New project', href: new_project_path)
- end
-
- it 'has a "New group" link' do
- render
-
- expect(rendered).to have_link('New group', href: new_group_path)
- end
-
- it 'has a "New snippet" link' do
- render
-
- expect(rendered).to have_link('New snippet', href: new_snippet_path)
- end
-
- context 'when partial exists in a menu item' do
- it 'renders the menu item partial without rendering invite modal partial' do
- view_model = {
- title: '_title_',
- menu_sections: [
- {
- title: '_section_title_',
- menu_items: [
- ::Gitlab::Nav::TopNavMenuItem
- .build(id: '_id_', title: '_title_', partial: 'groups/invite_members_top_nav_link')
- ]
- }
- ]
- }
-
- allow(view).to receive(:new_dropdown_view_model).and_return(view_model)
-
- render
-
- expect(response).to render_template(partial: 'groups/_invite_members_top_nav_link')
- end
- end
-
- context 'when the user is not allowed to do anything' do
- let(:user) { create(:user, :external) } # rubocop:disable RSpec/FactoryBot/AvoidCreate
-
- before do
- allow(user).to receive(:can?).and_call_original
- allow(user).to receive(:can?).with(:create_organization).and_return(false)
- end
-
- it 'is nil' do
- # We have to use `view.render` because `render` causes issues
- # https://github.com/rails/rails/issues/41320
- expect(view.render("layouts/header/new_dropdown")).to be_nil
- end
- end
- end
-
- def stub_current_user(current_user)
- allow(view).to receive(:current_user).and_return(current_user)
- end
-end