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-04-05 15:13:17 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-04-05 15:13:17 +0300
commitcd17aa65132de074aab9ae50ab7bbf7f16428546 (patch)
tree5a195a869320321aa9c3891e7ba5bbc9b9fc5d87 /spec
parent508f0c4ee719abb1294684eea4a63aa44cd23597 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/factories/member_roles.rb11
-rw-r--r--spec/features/dashboard/snippets_spec.rb3
-rw-r--r--spec/frontend/groups/components/empty_states/archived_projects_empty_state_spec.js4
-rw-r--r--spec/frontend/groups/components/empty_states/shared_projects_empty_state_spec.js4
-rw-r--r--spec/frontend/groups/components/empty_states/subgroups_and_projects_empty_state_spec.js1
-rw-r--r--spec/frontend/groups/components/overview_tabs_spec.js1
-rw-r--r--spec/helpers/application_helper_spec.rb23
-rw-r--r--spec/helpers/groups_helper_spec.rb1
-rw-r--r--spec/lib/gitlab/auth/u2f_webauthn_converter_spec.rb29
-rw-r--r--spec/lib/gitlab/background_migration/migrate_u2f_webauthn_spec.rb67
-rw-r--r--spec/lib/gitlab/tracking/destinations/database_events_snowplow_spec.rb113
-rw-r--r--spec/lib/gitlab/tracking_spec.rb123
-rw-r--r--spec/mailers/emails/service_desk_spec.rb39
-rw-r--r--spec/models/analytics/cycle_analytics/stage_spec.rb40
-rw-r--r--spec/models/concerns/database_event_tracking_spec.rb11
-rw-r--r--spec/models/u2f_registration_spec.rb66
-rw-r--r--spec/requests/api/npm_project_packages_spec.rb43
-rw-r--r--spec/scripts/create_pipeline_failure_incident_spec.rb162
-rw-r--r--spec/scripts/generate_failed_pipeline_slack_message_spec.rb81
-rw-r--r--spec/support/helpers/snowplow_helpers.rb10
-rw-r--r--spec/support/rspec_order_todo.yml1
-rw-r--r--spec/support/shared_examples/requests/api/packages_shared_examples.rb12
22 files changed, 352 insertions, 493 deletions
diff --git a/spec/factories/member_roles.rb b/spec/factories/member_roles.rb
deleted file mode 100644
index 503438d2521..00000000000
--- a/spec/factories/member_roles.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-FactoryBot.define do
- factory :member_role do
- namespace { association(:group) }
- base_access_level { Gitlab::Access::DEVELOPER }
-
- trait(:developer) { base_access_level { Gitlab::Access::DEVELOPER } }
- trait(:guest) { base_access_level { Gitlab::Access::GUEST } }
- end
-end
diff --git a/spec/features/dashboard/snippets_spec.rb b/spec/features/dashboard/snippets_spec.rb
index 24e47dc43ae..da985c6dc07 100644
--- a/spec/features/dashboard/snippets_spec.rb
+++ b/spec/features/dashboard/snippets_spec.rb
@@ -44,7 +44,8 @@ RSpec.describe 'Dashboard snippets', feature_category: :source_code_management d
element = page.find('.row.empty-state')
expect(element).to have_content("Code snippets")
- expect(element.find('.svg-content img.js-lazy-loaded')['src']).to have_content('illustrations/snippets_empty')
+ expect(element.find('.svg-content img.js-lazy-loaded')['src'])
+ .to have_content('illustrations/empty-state/empty-snippets-md')
end
it 'shows new snippet button in main content area' do
diff --git a/spec/frontend/groups/components/empty_states/archived_projects_empty_state_spec.js b/spec/frontend/groups/components/empty_states/archived_projects_empty_state_spec.js
index be61ffa92b4..bb3c0bc1526 100644
--- a/spec/frontend/groups/components/empty_states/archived_projects_empty_state_spec.js
+++ b/spec/frontend/groups/components/empty_states/archived_projects_empty_state_spec.js
@@ -6,7 +6,7 @@ import ArchivedProjectsEmptyState from '~/groups/components/empty_states/archive
let wrapper;
const defaultProvide = {
- newProjectIllustration: '/assets/illustrations/project-create-new-sm.svg',
+ emptyProjectsIllustration: '/assets/llustrations/empty-state/empty-projects-md.svg',
};
const createComponent = () => {
@@ -21,7 +21,7 @@ describe('ArchivedProjectsEmptyState', () => {
expect(wrapper.findComponent(GlEmptyState).props()).toMatchObject({
title: ArchivedProjectsEmptyState.i18n.title,
- svgPath: defaultProvide.newProjectIllustration,
+ svgPath: defaultProvide.emptyProjectsIllustration,
});
});
});
diff --git a/spec/frontend/groups/components/empty_states/shared_projects_empty_state_spec.js b/spec/frontend/groups/components/empty_states/shared_projects_empty_state_spec.js
index c4ace1be1f3..8ba1c480d5e 100644
--- a/spec/frontend/groups/components/empty_states/shared_projects_empty_state_spec.js
+++ b/spec/frontend/groups/components/empty_states/shared_projects_empty_state_spec.js
@@ -6,7 +6,7 @@ import SharedProjectsEmptyState from '~/groups/components/empty_states/shared_pr
let wrapper;
const defaultProvide = {
- newProjectIllustration: '/assets/illustrations/project-create-new-sm.svg',
+ emptyProjectsIllustration: '/assets/illustrations/empty-state/empty-projects-md.svg',
};
const createComponent = () => {
@@ -21,7 +21,7 @@ describe('SharedProjectsEmptyState', () => {
expect(wrapper.findComponent(GlEmptyState).props()).toMatchObject({
title: SharedProjectsEmptyState.i18n.title,
- svgPath: defaultProvide.newProjectIllustration,
+ svgPath: defaultProvide.emptyProjectsIllustration,
});
});
});
diff --git a/spec/frontend/groups/components/empty_states/subgroups_and_projects_empty_state_spec.js b/spec/frontend/groups/components/empty_states/subgroups_and_projects_empty_state_spec.js
index dc4271b98ee..5ae4d0be7d6 100644
--- a/spec/frontend/groups/components/empty_states/subgroups_and_projects_empty_state_spec.js
+++ b/spec/frontend/groups/components/empty_states/subgroups_and_projects_empty_state_spec.js
@@ -10,6 +10,7 @@ const defaultProvide = {
newProjectPath: '/projects/new?namespace_id=231',
newSubgroupIllustration: '/assets/illustrations/group-new.svg',
newSubgroupPath: '/groups/new?parent_id=231',
+ emptyProjectsIllustration: '/assets/illustrations/empty-state/empty-projects-md.svg',
emptySubgroupIllustration: '/assets/illustrations/empty-state/empty-subgroup-md.svg',
canCreateSubgroups: true,
canCreateProjects: true,
diff --git a/spec/frontend/groups/components/overview_tabs_spec.js b/spec/frontend/groups/components/overview_tabs_spec.js
index 906609c97f9..101dd06d578 100644
--- a/spec/frontend/groups/components/overview_tabs_spec.js
+++ b/spec/frontend/groups/components/overview_tabs_spec.js
@@ -39,6 +39,7 @@ describe('OverviewTabs', () => {
newProjectPath: 'projects/new',
newSubgroupIllustration: '',
newProjectIllustration: '',
+ emptyProjectsIllustration: '',
emptySubgroupIllustration: '',
canCreateSubgroups: false,
canCreateProjects: false,
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index bb1a4d57cc0..00d5308d552 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -706,4 +706,27 @@ RSpec.describe ApplicationHelper do
expect(helper.stylesheet_link_tag_defer('test')).to eq( '<link rel="stylesheet" media="screen" href="/stylesheets/test.css" />')
end
end
+
+ describe 'sign_in_with_redirect?' do
+ context 'when on the sign-in page that redirects afterwards' do
+ before do
+ allow(helper).to receive(:current_page?).and_return(true)
+ session[:user_return_to] = true
+ end
+
+ it 'returns true' do
+ expect(helper.sign_in_with_redirect?).to be_truthy
+ end
+ end
+
+ context 'when on a non sign-in page' do
+ before do
+ allow(helper).to receive(:current_page?).and_return(false)
+ end
+
+ it 'returns false' do
+ expect(helper.sign_in_with_redirect?).to be_falsey
+ end
+ end
+ end
end
diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb
index ce439e5bcdd..f66f9a8a58e 100644
--- a/spec/helpers/groups_helper_spec.rb
+++ b/spec/helpers/groups_helper_spec.rb
@@ -497,6 +497,7 @@ RSpec.describe GroupsHelper do
new_project_path: including("/projects/new?namespace_id=#{group.id}"),
new_subgroup_illustration: including('illustrations/subgroup-create-new-sm'),
new_project_illustration: including('illustrations/project-create-new-sm'),
+ empty_projects_illustration: including('illustrations/empty-state/empty-projects-md'),
empty_subgroup_illustration: including('illustrations/empty-state/empty-subgroup-md'),
render_empty_state: 'true',
can_create_subgroups: 'true',
diff --git a/spec/lib/gitlab/auth/u2f_webauthn_converter_spec.rb b/spec/lib/gitlab/auth/u2f_webauthn_converter_spec.rb
deleted file mode 100644
index deddc7f5294..00000000000
--- a/spec/lib/gitlab/auth/u2f_webauthn_converter_spec.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Auth::U2fWebauthnConverter do
- let_it_be(:u2f_registration) do
- device = U2F::FakeU2F.new(FFaker::BaconIpsum.characters(5))
- create(:u2f_registration, name: 'u2f_device',
- certificate: Base64.strict_encode64(device.cert_raw),
- key_handle: U2F.urlsafe_encode64(device.key_handle_raw),
- public_key: Base64.strict_encode64(device.origin_public_key_raw))
- end
-
- it 'converts u2f registration' do
- webauthn_credential = WebAuthn::U2fMigrator.new(
- app_id: Gitlab.config.gitlab.url,
- certificate: u2f_registration.certificate,
- key_handle: u2f_registration.key_handle,
- public_key: u2f_registration.public_key,
- counter: u2f_registration.counter
- ).credential
-
- converted_webauthn = described_class.new(u2f_registration).convert
-
- expect(converted_webauthn).to(
- include(user_id: u2f_registration.user_id,
- credential_xid: Base64.strict_encode64(webauthn_credential.id)))
- end
-end
diff --git a/spec/lib/gitlab/background_migration/migrate_u2f_webauthn_spec.rb b/spec/lib/gitlab/background_migration/migrate_u2f_webauthn_spec.rb
deleted file mode 100644
index 6554ee9d7b5..00000000000
--- a/spec/lib/gitlab/background_migration/migrate_u2f_webauthn_spec.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-require 'webauthn/u2f_migrator'
-
-RSpec.describe Gitlab::BackgroundMigration::MigrateU2fWebauthn, :migration, schema: 20211202041233 do
- let(:users) { table(:users) }
-
- let(:user) { users.create!(email: 'email@email.com', name: 'foo', username: 'foo', projects_limit: 0) }
-
- let(:u2f_registrations) { table(:u2f_registrations) }
- let(:webauthn_registrations) { table(:webauthn_registrations) }
-
- let!(:u2f_registration_not_migrated) { create_u2f_registration(1, 'reg1') }
- let!(:u2f_registration_not_migrated_no_name) { create_u2f_registration(2, nil, 2) }
- let!(:u2f_registration_migrated) { create_u2f_registration(3, 'reg3') }
-
- subject { described_class.new.perform(1, 3) }
-
- before do
- converted_credential = convert_credential_for(u2f_registration_migrated)
- webauthn_registrations.create!(converted_credential)
- end
-
- it 'migrates all records' do
- expect { subject }.to change { webauthn_registrations.count }.from(1).to(3)
-
- all_webauthn_registrations = webauthn_registrations.all.map(&:attributes)
-
- [u2f_registration_not_migrated, u2f_registration_not_migrated_no_name].each do |u2f_registration|
- expected_credential = convert_credential_for(u2f_registration).except(:created_at).stringify_keys
- expect(all_webauthn_registrations).to include(a_hash_including(expected_credential))
- end
- end
-
- def create_u2f_registration(id, name, counter = 5)
- device = U2F::FakeU2F.new(FFaker::BaconIpsum.characters(5))
- u2f_registrations.create!({ id: id,
- certificate: Base64.strict_encode64(device.cert_raw),
- key_handle: U2F.urlsafe_encode64(device.key_handle_raw),
- public_key: Base64.strict_encode64(device.origin_public_key_raw),
- counter: counter,
- name: name,
- user_id: user.id })
- end
-
- def convert_credential_for(u2f_registration)
- converted_credential = WebAuthn::U2fMigrator.new(
- app_id: Gitlab.config.gitlab.url,
- certificate: u2f_registration.certificate,
- key_handle: u2f_registration.key_handle,
- public_key: u2f_registration.public_key,
- counter: u2f_registration.counter
- ).credential
-
- {
- credential_xid: Base64.strict_encode64(converted_credential.id),
- public_key: Base64.strict_encode64(converted_credential.public_key),
- counter: u2f_registration.counter,
- name: u2f_registration.name || '',
- user_id: u2f_registration.user_id,
- u2f_registration_id: u2f_registration.id,
- created_at: u2f_registration.created_at
- }
- end
-end
diff --git a/spec/lib/gitlab/tracking/destinations/database_events_snowplow_spec.rb b/spec/lib/gitlab/tracking/destinations/database_events_snowplow_spec.rb
new file mode 100644
index 00000000000..0f2082c1f25
--- /dev/null
+++ b/spec/lib/gitlab/tracking/destinations/database_events_snowplow_spec.rb
@@ -0,0 +1,113 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Tracking::Destinations::DatabaseEventsSnowplow, :do_not_stub_snowplow_by_default, feature_category: :application_instrumentation do
+ let(:emitter) { SnowplowTracker::Emitter.new(endpoint: 'localhost', options: { buffer_size: 1 }) }
+
+ let(:tracker) do
+ SnowplowTracker::Tracker
+ .new(
+ emitters: [emitter],
+ subject: SnowplowTracker::Subject.new,
+ namespace: 'namespace',
+ app_id: 'app_id'
+ )
+ end
+
+ before do
+ stub_application_setting(snowplow_app_id: '_abc123_')
+ end
+
+ around do |example|
+ freeze_time { example.run }
+ end
+
+ context 'when snowplow is enabled' do
+ before do
+ allow(SnowplowTracker::AsyncEmitter)
+ .to receive(:new)
+ .with(endpoint: 'localhost:9091',
+ options:
+ {
+ protocol: 'https',
+ on_success: subject.method(:increment_successful_events_emissions),
+ on_failure: subject.method(:failure_callback)
+ }
+ ).and_return(emitter)
+
+ allow(SnowplowTracker::Tracker)
+ .to receive(:new)
+ .with(
+ emitters: [emitter],
+ subject: an_instance_of(SnowplowTracker::Subject),
+ namespace: described_class::SNOWPLOW_NAMESPACE,
+ app_id: '_abc123_'
+ ).and_return(tracker)
+ end
+
+ describe '#event' do
+ it 'sends event to tracker' do
+ allow(tracker).to receive(:track_struct_event).and_call_original
+
+ subject.event('category', 'action', label: 'label', property: 'property', value: 1.5)
+
+ expect(tracker)
+ .to have_received(:track_struct_event)
+ .with(category: 'category', action: 'action', label: 'label', property: 'property', value: 1.5, context: nil,
+ tstamp: (Time.now.to_f * 1000).to_i)
+ end
+
+ it 'increase total snowplow events counter' do
+ counter = double
+
+ expect(counter).to receive(:increment)
+ expect(Gitlab::Metrics).to receive(:counter)
+ .with(:gitlab_db_events_snowplow_events_total, 'Number of Snowplow events')
+ .and_return(counter)
+
+ subject.event('category', 'action', label: 'label', property: 'property', value: 1.5)
+ end
+ end
+ end
+
+ context 'for callbacks' do
+ describe 'on success' do
+ it 'increase gitlab_successful_snowplow_events_total counter' do
+ counter = double
+
+ expect(counter).to receive(:increment).with({}, 2)
+ expect(Gitlab::Metrics).to receive(:counter)
+ .with(
+ :gitlab_db_events_snowplow_successful_events_total,
+ 'Number of successful Snowplow events emissions').and_return(counter)
+
+ subject.method(:increment_successful_events_emissions).call(2)
+ end
+ end
+
+ describe 'on failure' do
+ it 'increase gitlab_failed_snowplow_events_total counter and logs failures', :aggregate_failures do
+ counter = double
+ error_message = "Issue database_event_update failed to be reported to collector at localhost:9091"
+ failures = [{ "e" => "se",
+ "se_ca" => "Issue",
+ "se_la" => "issues",
+ "se_ac" => "database_event_update" }]
+ allow(Gitlab::Metrics).to receive(:counter)
+ .with(
+ :gitlab_db_events_snowplow_successful_events_total,
+ 'Number of successful Snowplow events emissions').and_call_original
+
+ expect(Gitlab::AppLogger).to receive(:error).with(error_message)
+ expect(counter).to receive(:increment).with({}, 1)
+ expect(Gitlab::Metrics).to receive(:counter)
+ .with(
+ :gitlab_db_events_snowplow_failed_events_total,
+ 'Number of failed Snowplow events emissions').and_return(counter)
+
+ subject.method(:failure_callback).call(2, failures)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/tracking_spec.rb b/spec/lib/gitlab/tracking_spec.rb
index e79bb2ef129..56be80678e9 100644
--- a/spec/lib/gitlab/tracking_spec.rb
+++ b/spec/lib/gitlab/tracking_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe Gitlab::Tracking do
+RSpec.describe Gitlab::Tracking, feature_category: :application_instrumentation do
include StubENV
before do
@@ -102,12 +102,28 @@ RSpec.describe Gitlab::Tracking do
end
end
- describe '.event' do
+ context 'event tracking' do
let(:namespace) { create(:namespace) }
- shared_examples 'delegates to destination' do |klass|
+ shared_examples 'rescued error raised by destination class' do
+ it 'rescues error' do
+ error = StandardError.new("something went wrong")
+ allow_any_instance_of(destination_class).to receive(:event).and_raise(error)
+
+ expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception)
+ .with(
+ error,
+ snowplow_category: category,
+ snowplow_action: action
+ )
+
+ expect { tracking_method }.not_to raise_error
+ end
+ end
+
+ shared_examples 'delegates to destination' do |klass, method|
before do
- allow_any_instance_of(Gitlab::Tracking::Destinations::Snowplow).to receive(:event)
+ allow_any_instance_of(klass).to receive(:event)
end
it "delegates to #{klass} destination" do
@@ -118,8 +134,8 @@ RSpec.describe Gitlab::Tracking do
expect(Gitlab::Tracking::StandardContext)
.to receive(:new)
- .with(project: project, user: user, namespace: namespace, extra_key_1: 'extra value 1', extra_key_2: 'extra value 2')
- .and_call_original
+ .with(project: project, user: user, namespace: namespace, extra_key_1: 'extra value 1', extra_key_2: 'extra value 2')
+ .and_call_original
expect_any_instance_of(klass).to receive(:event) do |_, category, action, args|
expect(category).to eq('category')
@@ -132,7 +148,7 @@ RSpec.describe Gitlab::Tracking do
expect(args[:context].last).to eq(other_context)
end
- described_class.event('category', 'action',
+ described_class.method(method).call('category', 'action',
label: 'label',
property: 'property',
value: 1.5,
@@ -141,44 +157,95 @@ RSpec.describe Gitlab::Tracking do
user: user,
namespace: namespace,
extra_key_1: 'extra value 1',
- extra_key_2: 'extra value 2')
+ extra_key_2: 'extra value 2'
+ )
end
end
- context 'when the action is not passed in as a string' do
- it 'allows symbols' do
- expect(Gitlab::ErrorTracking).not_to receive(:track_and_raise_for_dev_exception)
+ describe '.database_event' do
+ context 'when the action is not passed in as a string' do
+ it 'allows symbols' do
+ expect(Gitlab::ErrorTracking).not_to receive(:track_and_raise_for_dev_exception)
- described_class.event('category', :some_action)
- end
+ described_class.database_event('category', :some_action)
+ end
+
+ it 'allows nil' do
+ expect(Gitlab::ErrorTracking).not_to receive(:track_and_raise_for_dev_exception)
+
+ described_class.database_event('category', nil)
+ end
- it 'allows nil' do
- expect(Gitlab::ErrorTracking).not_to receive(:track_and_raise_for_dev_exception)
+ it 'allows integers' do
+ expect(Gitlab::ErrorTracking).not_to receive(:track_and_raise_for_dev_exception)
- described_class.event('category', nil)
+ described_class.database_event('category', 1)
+ end
end
- it 'allows integers' do
- expect(Gitlab::ErrorTracking).not_to receive(:track_and_raise_for_dev_exception)
+ it_behaves_like 'rescued error raised by destination class' do
+ let(:category) { 'Issue' }
+ let(:action) { 'created' }
+ let(:destination_class) { Gitlab::Tracking::Destinations::DatabaseEventsSnowplow }
- described_class.event('category', 1)
+ subject(:tracking_method) { described_class.database_event(category, action) }
end
+
+ it_behaves_like 'delegates to destination', Gitlab::Tracking::Destinations::DatabaseEventsSnowplow, :database_event
end
- context 'when destination is Snowplow' do
- before do
- allow(Rails.env).to receive(:development?).and_return(true)
+ describe '.event' do
+ context 'when the action is not passed in as a string' do
+ it 'allows symbols' do
+ expect(Gitlab::ErrorTracking).not_to receive(:track_and_raise_for_dev_exception)
+
+ described_class.event('category', :some_action)
+ end
+
+ it 'allows nil' do
+ expect(Gitlab::ErrorTracking).not_to receive(:track_and_raise_for_dev_exception)
+
+ described_class.event('category', nil)
+ end
+
+ it 'allows integers' do
+ expect(Gitlab::ErrorTracking).not_to receive(:track_and_raise_for_dev_exception)
+
+ described_class.event('category', 1)
+ end
end
- it_behaves_like 'delegates to destination', Gitlab::Tracking::Destinations::Snowplow
- end
+ context 'when destination is Snowplow' do
+ before do
+ allow(Rails.env).to receive(:development?).and_return(true)
+ end
- context 'when destination is SnowplowMicro' do
- before do
- allow(Rails.env).to receive(:development?).and_return(true)
+ it_behaves_like 'rescued error raised by destination class' do
+ let(:category) { 'category' }
+ let(:action) { 'action' }
+ let(:destination_class) { Gitlab::Tracking::Destinations::Snowplow }
+
+ subject(:tracking_method) { described_class.event(category, action) }
+ end
+
+ it_behaves_like 'delegates to destination', Gitlab::Tracking::Destinations::Snowplow, :event
end
- it_behaves_like 'delegates to destination', Gitlab::Tracking::Destinations::SnowplowMicro
+ context 'when destination is SnowplowMicro' do
+ before do
+ allow(Rails.env).to receive(:development?).and_return(true)
+ end
+
+ it_behaves_like 'rescued error raised by destination class' do
+ let(:category) { 'category' }
+ let(:action) { 'action' }
+ let(:destination_class) { Gitlab::Tracking::Destinations::Snowplow }
+
+ subject(:tracking_method) { described_class.event(category, action) }
+ end
+
+ it_behaves_like 'delegates to destination', Gitlab::Tracking::Destinations::SnowplowMicro, :event
+ end
end
end
diff --git a/spec/mailers/emails/service_desk_spec.rb b/spec/mailers/emails/service_desk_spec.rb
index 25afa8b48ce..b81c0ec8617 100644
--- a/spec/mailers/emails/service_desk_spec.rb
+++ b/spec/mailers/emails/service_desk_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require 'email_spec'
-RSpec.describe Emails::ServiceDesk do
+RSpec.describe Emails::ServiceDesk, feature_category: :service_desk do
include EmailSpec::Helpers
include EmailSpec::Matchers
include EmailHelpers
@@ -16,6 +16,9 @@ RSpec.describe Emails::ServiceDesk do
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:email) { 'someone@gitlab.com' }
let_it_be(:expected_unsubscribe_url) { unsubscribe_sent_notification_url('b7721fc7e8419911a8bea145236a0519') }
+ let_it_be(:credential) { create(:service_desk_custom_email_credential, project: project) }
+ let_it_be(:verification) { create(:service_desk_custom_email_verification, project: project) }
+ let_it_be(:service_desk_setting) { create(:service_desk_setting, project: project, custom_email: 'user@example.com') }
let(:template) { double(content: template_content) }
@@ -81,6 +84,24 @@ RSpec.describe Emails::ServiceDesk do
end
end
+ shared_examples 'a custom email verification process email' do
+ it 'contains custom email and project in subject' do
+ expect(subject.subject).to include(service_desk_setting.custom_email)
+ expect(subject.subject).to include(service_desk_setting.project.name)
+ end
+ end
+
+ shared_examples 'a custom email verification process notification email' do
+ it 'has correct recipient' do
+ expect(subject.to).to eq(['owner@example.com'])
+ end
+
+ it 'contains custom email and project in body' do
+ is_expected.to have_body_text(service_desk_setting.custom_email)
+ is_expected.to have_body_text(service_desk_setting.project.name)
+ end
+ end
+
describe '.service_desk_thank_you_email' do
let_it_be(:reply_in_subject) { true }
let_it_be(:default_text) do
@@ -305,4 +326,20 @@ RSpec.describe Emails::ServiceDesk do
end
end
end
+
+ describe '.service_desk_verification_triggered_email' do
+ before do
+ service_desk_setting.custom_email_verification.triggerer = user
+ end
+
+ subject { Notify.service_desk_verification_triggered_email(service_desk_setting, 'owner@example.com') }
+
+ it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'a custom email verification process email'
+ it_behaves_like 'a custom email verification process notification email'
+
+ it 'contains triggerer username' do
+ is_expected.to have_body_text("@#{user.username}")
+ end
+ end
end
diff --git a/spec/models/analytics/cycle_analytics/stage_spec.rb b/spec/models/analytics/cycle_analytics/stage_spec.rb
index 57748f8942e..44c0be68fe3 100644
--- a/spec/models/analytics/cycle_analytics/stage_spec.rb
+++ b/spec/models/analytics/cycle_analytics/stage_spec.rb
@@ -105,30 +105,36 @@ RSpec.describe Analytics::CycleAnalytics::Stage, feature_category: :value_stream
}
end
- describe '#create' do
- it_behaves_like 'Snowplow event tracking' do
- let(:property) { 'create' }
- let(:extra) { record_tracked_attributes }
+ context 'with database event tracking' do
+ before do
+ allow(Gitlab::Tracking).to receive(:database_event).and_call_original
+ end
+
+ describe '#create' do
+ it_behaves_like 'Snowplow event tracking', overrides: { tracking_method: :database_event } do
+ let(:property) { 'create' }
+ let(:extra) { record_tracked_attributes }
- subject(:new_group_stage) { stage }
+ subject(:new_group_stage) { stage }
+ end
end
- end
- describe '#update', :freeze_time do
- it_behaves_like 'Snowplow event tracking' do
- subject(:create_group_stage) { stage.update!(name: 'st 2') }
+ describe '#update', :freeze_time do
+ it_behaves_like 'Snowplow event tracking', overrides: { tracking_method: :database_event } do
+ subject(:create_group_stage) { stage.update!(name: 'st 2') }
- let(:extra) { record_tracked_attributes.merge('name' => 'st 2') }
- let(:property) { 'update' }
+ let(:extra) { record_tracked_attributes.merge('name' => 'st 2') }
+ let(:property) { 'update' }
+ end
end
- end
- describe '#destroy' do
- it_behaves_like 'Snowplow event tracking' do
- subject(:delete_stage_group) { stage.destroy! }
+ describe '#destroy' do
+ it_behaves_like 'Snowplow event tracking', overrides: { tracking_method: :database_event } do
+ subject(:delete_stage_group) { stage.destroy! }
- let(:extra) { record_tracked_attributes }
- let(:property) { 'destroy' }
+ let(:extra) { record_tracked_attributes }
+ let(:property) { 'destroy' }
+ end
end
end
end
diff --git a/spec/models/concerns/database_event_tracking_spec.rb b/spec/models/concerns/database_event_tracking_spec.rb
index 87aa8275635..cad82f971b3 100644
--- a/spec/models/concerns/database_event_tracking_spec.rb
+++ b/spec/models/concerns/database_event_tracking_spec.rb
@@ -3,6 +3,10 @@
require 'spec_helper'
RSpec.describe DatabaseEventTracking, :snowplow do
+ before do
+ allow(Gitlab::Tracking).to receive(:database_event).and_call_original
+ end
+
let(:test_class) do
Class.new(ActiveRecord::Base) do
include DatabaseEventTracking
@@ -17,7 +21,7 @@ RSpec.describe DatabaseEventTracking, :snowplow do
context 'if event emmiter failed' do
before do
- allow(Gitlab::Tracking).to receive(:event).and_raise(StandardError) # rubocop:disable RSpec/ExpectGitlabTracking
+ allow(Gitlab::Tracking).to receive(:database_event).and_raise(StandardError) # rubocop:disable RSpec/ExpectGitlabTracking
end
it 'tracks the exception' do
@@ -35,7 +39,7 @@ RSpec.describe DatabaseEventTracking, :snowplow do
it 'does not track the event' do
create_test_class_record
- expect_no_snowplow_event
+ expect_no_snowplow_event(tracking_method: :database_event)
end
end
@@ -47,6 +51,7 @@ RSpec.describe DatabaseEventTracking, :snowplow do
create_test_class_record
expect_snowplow_event(
+ tracking_method: :database_event,
category: category,
action: "#{event}_create",
label: 'application_setting_terms',
@@ -61,6 +66,7 @@ RSpec.describe DatabaseEventTracking, :snowplow do
test_class.first.update!(id: 3)
expect_snowplow_event(
+ tracking_method: :database_event,
category: category,
action: "#{event}_update",
label: 'application_setting_terms',
@@ -75,6 +81,7 @@ RSpec.describe DatabaseEventTracking, :snowplow do
test_class.first.destroy!
expect_snowplow_event(
+ tracking_method: :database_event,
category: category,
action: "#{event}_destroy",
label: 'application_setting_terms',
diff --git a/spec/models/u2f_registration_spec.rb b/spec/models/u2f_registration_spec.rb
index 1fab3882c2a..9c8d786ecb1 100644
--- a/spec/models/u2f_registration_spec.rb
+++ b/spec/models/u2f_registration_spec.rb
@@ -62,72 +62,6 @@ RSpec.describe U2fRegistration do
end
end
- describe 'callbacks' do
- describe 'after create' do
- shared_examples_for 'creates webauthn registration' do
- it 'creates webauthn registration' do
- u2f_registration = create_u2f_registration
- webauthn_registration = WebauthnRegistration.where(u2f_registration_id: u2f_registration.id)
- expect(webauthn_registration).to exist
- end
- end
-
- it_behaves_like 'creates webauthn registration'
-
- context 'when the u2f_registration has a blank name' do
- let(:u2f_registration_name) { '' }
-
- it_behaves_like 'creates webauthn registration'
- end
-
- context 'when the u2f_registration has the name as `nil`' do
- let(:u2f_registration_name) { nil }
-
- it_behaves_like 'creates webauthn registration'
- end
-
- it 'logs error' do
- allow(Gitlab::Auth::U2fWebauthnConverter).to receive(:new).and_raise('boom!')
-
- allow_next_instance_of(U2fRegistration) do |u2f_registration|
- allow(u2f_registration).to receive(:id).and_return(123)
- end
-
- expect(Gitlab::ErrorTracking).to(
- receive(:track_exception).with(kind_of(StandardError),
- u2f_registration_id: 123))
-
- create_u2f_registration
- end
- end
-
- describe 'after update' do
- context 'when counter is updated' do
- it 'updates the webauthn registration counter to be the same value' do
- u2f_registration = create_u2f_registration
- new_counter = u2f_registration.counter + 1
- webauthn_registration = WebauthnRegistration.find_by(u2f_registration_id: u2f_registration.id)
-
- u2f_registration.update!(counter: new_counter)
-
- expect(u2f_registration.reload.counter).to eq(new_counter)
- expect(webauthn_registration.reload.counter).to eq(new_counter)
- end
- end
-
- context 'when sign count of registration is not updated' do
- it 'does not update the counter' do
- u2f_registration = create_u2f_registration
- webauthn_registration = WebauthnRegistration.find_by(u2f_registration_id: u2f_registration.id)
-
- expect do
- u2f_registration.update!(name: 'a new name')
- end.not_to change { webauthn_registration.counter }
- end
- end
- end
- end
-
def create_u2f_registration
create(
:u2f_registration,
diff --git a/spec/requests/api/npm_project_packages_spec.rb b/spec/requests/api/npm_project_packages_spec.rb
index c738269fce0..c4e0d5ed27b 100644
--- a/spec/requests/api/npm_project_packages_spec.rb
+++ b/spec/requests/api/npm_project_packages_spec.rb
@@ -226,15 +226,7 @@ RSpec.describe API::NpmProjectPackages, feature_category: :package_registry do
context 'with access token' do
it_behaves_like 'a package tracking event', 'API::NpmPackages', 'push_package'
- it 'creates npm package with file' do
- expect { subject }
- .to change { project.packages.count }.by(1)
- .and change { Packages::PackageFile.count }.by(1)
- .and change { Packages::Tag.count }.by(1)
- .and change { Packages::Npm::Metadatum.count }.by(1)
-
- expect(response).to have_gitlab_http_status(:ok)
- end
+ it_behaves_like 'a successful package creation'
end
it 'creates npm package with file with job token' do
@@ -391,20 +383,35 @@ RSpec.describe API::NpmProjectPackages, feature_category: :package_registry do
context 'with a too large metadata structure' do
let(:package_name) { "@#{group.path}/my_package_name" }
- let(:params) do
- upload_params(package_name: package_name, package_version: '1.2.3').tap do |h|
- h['versions']['1.2.3']['test'] = 'test' * 10000
+
+ ::Packages::Npm::CreatePackageService::PACKAGE_JSON_NOT_ALLOWED_FIELDS.each do |field|
+ context "when a large value for #{field} is set" do
+ let(:params) do
+ upload_params(package_name: package_name, package_version: '1.2.3').tap do |h|
+ h['versions']['1.2.3'][field] = 'test' * 10000
+ end
+ end
+
+ it_behaves_like 'a successful package creation'
end
end
- it_behaves_like 'not a package tracking event'
+ context 'when the large field is not one of the ignored fields' do
+ let(:params) do
+ upload_params(package_name: package_name, package_version: '1.2.3').tap do |h|
+ h['versions']['1.2.3']['test'] = 'test' * 10000
+ end
+ end
- it 'returns an error' do
- expect { upload_package_with_token }
- .not_to change { project.packages.count }
+ it_behaves_like 'not a package tracking event'
- expect(response).to have_gitlab_http_status(:bad_request)
- expect(response.body).to include('Validation failed: Package json structure is too large')
+ it 'returns an error' do
+ expect { upload_package_with_token }
+ .not_to change { project.packages.count }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(response.body).to include('Validation failed: Package json structure is too large')
+ end
end
end
end
diff --git a/spec/scripts/create_pipeline_failure_incident_spec.rb b/spec/scripts/create_pipeline_failure_incident_spec.rb
deleted file mode 100644
index efbd22ccb32..00000000000
--- a/spec/scripts/create_pipeline_failure_incident_spec.rb
+++ /dev/null
@@ -1,162 +0,0 @@
-# frozen_string_literal: true
-
-require 'fast_spec_helper'
-require_relative '../../scripts/create-pipeline-failure-incident'
-require_relative '../support/helpers/stub_env'
-
-RSpec.describe CreatePipelineFailureIncident, feature_category: :tooling do
- include StubENV
-
- describe '#execute' do
- let(:create_issue) { instance_double(CreateIssue) }
- let(:issue) { double('Issue', iid: 1) } # rubocop:disable RSpec/VerifiedDoubles
- let(:create_issue_discussion) { instance_double(CreateIssueDiscussion, execute: true) }
- let(:failed_jobs) { instance_double(PipelineFailedJobs, execute: []) }
-
- let(:options) do
- {
- project: 'gitlab-org/gitlab-test-project',
- api_token: 'asdf1234'
- }
- end
-
- let(:issue_params) do
- {
- issue_type: 'incident',
- title: title,
- description: description,
- labels: incident_labels
- }
- end
-
- subject { described_class.new(options).execute }
-
- before do
- stub_env(
- 'CI_COMMIT_SHA' => 'bfcd2b9b5cad0b889494ce830697392c8ca11257',
- 'CI_PROJECT_PATH' => 'gitlab.com/gitlab-org/gitlab',
- 'CI_PROJECT_NAME' => 'gitlab',
- 'GITLAB_USER_ID' => '1111',
- 'CI_PROJECT_ID' => '13083',
- 'CI_PIPELINE_ID' => '1234567',
- 'CI_PIPELINE_URL' => 'https://gitlab.com/gitlab-org/gitlab/-/pipelines/1234567',
- 'CI_PROJECT_URL' => 'https://gitlab.com/gitlab-org/gitlab',
- 'CI_PIPELINE_CREATED_AT' => '2023-01-24 00:00:00',
- 'CI_COMMIT_TITLE' => 'Commit title',
- 'CI_PIPELINE_SOURCE' => 'push',
- 'GITLAB_USER_NAME' => 'Foo User',
- 'PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE' => 'asdf1234',
- 'CI_SERVER_URL' => 'https://gitlab.com',
- 'GITLAB_USER_LOGIN' => 'foo'
- )
- end
-
- shared_examples 'creating an issue' do
- it 'successfully creates an issue' do
- allow(PipelineFailedJobs).to receive(:new)
- .with(API::DEFAULT_OPTIONS.merge(exclude_allowed_to_fail_jobs: true))
- .and_return(failed_jobs)
-
- expect(CreateIssue).to receive(:new)
- .with(project: options[:project], api_token: options[:api_token])
- .and_return(create_issue)
-
- expect(CreateIssueDiscussion).to receive(:new)
- .with(project: options[:project], api_token: options[:api_token])
- .and_return(create_issue_discussion).twice
-
- expect(create_issue).to receive(:execute)
- .with(issue_params).and_return(issue)
-
- expect(subject).to eq(issue)
- end
- end
-
- context 'when stable branch' do
- let(:incident_labels) { ['release-blocker'] }
- let(:title) { /broken `15-6-stable-ee`/ }
- let(:description) { /A broken stable branch prevents patch releases/ }
-
- let(:commit_merge_request) do
- {
- 'author' => {
- 'id' => '2'
- },
- 'title' => 'foo',
- 'web_url' => 'https://gitlab.com/test'
- }
- end
-
- let(:merge_request) { instance_double(CommitMergeRequests, execute: [commit_merge_request]) }
- let(:issue_params) { super().merge(assignee_ids: [1111, 2]) }
-
- before do
- stub_env(
- 'CI_COMMIT_REF_NAME' => '15-6-stable-ee'
- )
-
- allow(CommitMergeRequests).to receive(:new)
- .with(API::DEFAULT_OPTIONS.merge(sha: ENV['CI_COMMIT_SHA']))
- .and_return(merge_request)
- end
-
- it_behaves_like 'creating an issue'
- end
-
- context 'when other branch' do
- let(:title) { /broken `master`/ }
- let(:description) { /Follow the \[Broken `master` handbook guide\]/ }
-
- before do
- stub_env(
- 'CI_COMMIT_REF_NAME' => 'master'
- )
- end
-
- context 'when GitLab FOSS' do
- let(:incident_labels) { ['master:foss-broken', 'Engineering Productivity', 'master-broken::undetermined'] }
-
- before do
- stub_env(
- 'CI_PROJECT_NAME' => 'gitlab-foss'
- )
- end
-
- it_behaves_like 'creating an issue'
- end
-
- context 'when GitLab EE' do
- let(:incident_labels) { ['master:broken', 'Engineering Productivity', 'master-broken::undetermined'] }
-
- before do
- stub_env(
- 'CI_PROJECT_NAME' => 'gitlab'
- )
- end
-
- it_behaves_like 'creating an issue'
- end
- end
-
- context 'when review-apps' do
- let(:options) do
- {
- project: 'gitlab-org/quality/engineering-productivity/review-apps-broken-incidents',
- api_token: 'asdf1234'
- }
- end
-
- let(:incident_labels) { ["review-apps-broken", "Engineering Productivity", "ep::review-apps"] }
- let(:title) { /broken `my-branch`/ }
- let(:description) { /Please refer to \[the review-apps triaging process\]/ }
-
- before do
- stub_env(
- 'CI_COMMIT_REF_NAME' => 'my-branch'
- )
- end
-
- it_behaves_like 'creating an issue'
- end
- end
-end
diff --git a/spec/scripts/generate_failed_pipeline_slack_message_spec.rb b/spec/scripts/generate_failed_pipeline_slack_message_spec.rb
deleted file mode 100644
index 2418116e694..00000000000
--- a/spec/scripts/generate_failed_pipeline_slack_message_spec.rb
+++ /dev/null
@@ -1,81 +0,0 @@
-# frozen_string_literal: true
-
-require 'fast_spec_helper'
-require_relative '../../scripts/generate-failed-pipeline-slack-message'
-require_relative '../support/helpers/stub_env'
-
-RSpec.describe GenerateFailedPipelineSlackMessage, feature_category: :tooling do
- include StubENV
-
- describe '#execute' do
- let(:create_issue) { instance_double(CreateIssue) }
- let(:issue) { double('Issue', iid: 1) } # rubocop:disable RSpec/VerifiedDoubles
- let(:create_issue_discussion) { instance_double(CreateIssueDiscussion, execute: true) }
- let(:failed_jobs) { instance_double(PipelineFailedJobs, execute: []) }
-
- let(:project_path) { 'gitlab-org/gitlab-test-project' }
- let(:options) do
- {
- project: project_path,
- incident_json_file: 'incident_json_file_tests.json'
- }
- end
-
- subject { described_class.new(options).execute }
-
- before do
- stub_env(
- 'CI_COMMIT_REF_NAME' => 'my-branch',
- 'CI_COMMIT_SHA' => 'bfcd2b9b5cad0b889494ce830697392c8ca11257',
- 'CI_COMMIT_TITLE' => 'Commit title',
- 'CI_PIPELINE_CREATED_AT' => '2023-01-24 00:00:00',
- 'CI_PIPELINE_ID' => '1234567',
- 'CI_PIPELINE_SOURCE' => 'push',
- 'CI_PIPELINE_URL' => 'https://gitlab.com/gitlab-org/gitlab/-/pipelines/1234567',
- 'CI_PROJECT_PATH' => 'gitlab.com/gitlab-org/gitlab',
- 'CI_PROJECT_URL' => 'https://gitlab.com/gitlab-org/gitlab',
- 'CI_SERVER_URL' => 'https://gitlab.com',
- 'GITLAB_USER_ID' => '1111',
- 'GITLAB_USER_LOGIN' => 'foo',
- 'GITLAB_USER_NAME' => 'Foo User',
- 'PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE' => 'asdf1234',
- 'SLACK_CHANNEL' => '#a-slack-channel'
- )
-
- allow(PipelineFailedJobs).to receive(:new)
- .with(API::DEFAULT_OPTIONS.merge(exclude_allowed_to_fail_jobs: true))
- .and_return(failed_jobs)
- end
-
- it 'returns the correct keys' do
- expect(subject.keys).to match_array([:channel, :username, :icon_emoji, :text, :blocks])
- end
-
- it 'returns the correct channel' do
- expect(subject[:channel]).to eq('#a-slack-channel')
- end
-
- it 'returns the correct username' do
- expect(subject[:username]).to eq('Failed pipeline reporter')
- end
-
- it 'returns the correct icon_emoji' do
- expect(subject[:icon_emoji]).to eq(':boom:')
- end
-
- it 'returns the correct text' do
- expect(subject[:text]).to eq(
- '*<https://gitlab.com/gitlab-org/gitlab|gitlab.com/gitlab-org/gitlab> pipeline ' \
- '<https://gitlab.com/gitlab-org/gitlab/-/pipelines/1234567|#1234567> failed*'
- )
- end
-
- it 'returns the correct incident button link' do
- block_with_incident_link = subject[:blocks].detect { |block| block.key?(:accessory) }
-
- expect(block_with_incident_link[:accessory][:url]).to eq(
- "https://gitlab.com/#{project_path}/-/issues/new?issuable_template=incident&issue%5Bissue_type%5D=incident"
- )
- end
- end
-end
diff --git a/spec/support/helpers/snowplow_helpers.rb b/spec/support/helpers/snowplow_helpers.rb
index 265e1c38b09..a04e5d46df9 100644
--- a/spec/support/helpers/snowplow_helpers.rb
+++ b/spec/support/helpers/snowplow_helpers.rb
@@ -46,7 +46,7 @@ module SnowplowHelpers
# }
# ]
# )
- def expect_snowplow_event(category:, action:, context: nil, **kwargs)
+ def expect_snowplow_event(category:, action:, context: nil, tracking_method: :event, **kwargs)
if context
if context.is_a?(Array)
kwargs[:context] = []
@@ -60,7 +60,7 @@ module SnowplowHelpers
end
end
- expect(Gitlab::Tracking).to have_received(:event) # rubocop:disable RSpec/ExpectGitlabTracking
+ expect(Gitlab::Tracking).to have_received(tracking_method) # rubocop:disable RSpec/ExpectGitlabTracking
.with(category, action, **kwargs).at_least(:once)
end
@@ -79,11 +79,11 @@ module SnowplowHelpers
# expect_no_snowplow_event
# end
# end
- def expect_no_snowplow_event(category: nil, action: nil, **kwargs)
+ def expect_no_snowplow_event(category: nil, action: nil, tracking_method: :event, **kwargs)
if category && action
- expect(Gitlab::Tracking).not_to have_received(:event).with(category, action, **kwargs) # rubocop:disable RSpec/ExpectGitlabTracking
+ expect(Gitlab::Tracking).not_to have_received(tracking_method).with(category, action, **kwargs) # rubocop:disable RSpec/ExpectGitlabTracking
else
- expect(Gitlab::Tracking).not_to have_received(:event) # rubocop:disable RSpec/ExpectGitlabTracking
+ expect(Gitlab::Tracking).not_to have_received(tracking_method) # rubocop:disable RSpec/ExpectGitlabTracking
end
end
end
diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml
index 5c7d31190fd..2058eeef442 100644
--- a/spec/support/rspec_order_todo.yml
+++ b/spec/support/rspec_order_todo.yml
@@ -5728,7 +5728,6 @@
- './spec/lib/gitlab/background_migration/migrate_personal_namespace_project_maintainer_to_owner_spec.rb'
- './spec/lib/gitlab/background_migration/migrate_project_taggings_context_from_tags_to_topics_spec.rb'
- './spec/lib/gitlab/background_migration/migrate_shimo_confluence_integration_category_spec.rb'
-- './spec/lib/gitlab/background_migration/migrate_u2f_webauthn_spec.rb'
- './spec/lib/gitlab/background_migration/move_container_registry_enabled_to_project_feature_spec.rb'
- './spec/lib/gitlab/background_migration/nullify_orphan_runner_id_on_ci_builds_spec.rb'
- './spec/lib/gitlab/background_migration/populate_container_repository_migration_plan_spec.rb'
diff --git a/spec/support/shared_examples/requests/api/packages_shared_examples.rb b/spec/support/shared_examples/requests/api/packages_shared_examples.rb
index b7f2805ed97..1f2450c864b 100644
--- a/spec/support/shared_examples/requests/api/packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/packages_shared_examples.rb
@@ -175,3 +175,15 @@ RSpec.shared_examples 'bumping the package last downloaded at field' do
.to change { package.reload.last_downloaded_at }.from(nil).to(instance_of(ActiveSupport::TimeWithZone))
end
end
+
+RSpec.shared_examples 'a successful package creation' do
+ it 'creates npm package with file' do
+ expect { subject }
+ .to change { project.packages.count }.by(1)
+ .and change { Packages::PackageFile.count }.by(1)
+ .and change { Packages::Tag.count }.by(1)
+ .and change { Packages::Npm::Metadatum.count }.by(1)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+end