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>2020-09-22 15:09:39 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-09-22 15:09:39 +0300
commit26879909dd0571b392f105373a700a314201cd53 (patch)
tree800cb6476926e919ce7cabdcadd58a1cdb3178e1 /spec
parent1086ac5177a6762ac14bccc6ce5584781bd44d1c (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/projects/import/jira_controller_spec.rb2
-rw-r--r--spec/factories/alert_management/alerts.rb14
-rw-r--r--spec/factories/alerting/alert.rb25
-rw-r--r--spec/frontend/packages/shared/components/__snapshots__/package_list_row_spec.js.snap25
-rw-r--r--spec/frontend/packages/shared/components/package_list_row_spec.js8
-rw-r--r--spec/frontend/packages/shared/components/package_path_spec.js86
-rw-r--r--spec/lib/gitlab/alert_management/alert_params_spec.rb101
-rw-r--r--spec/lib/gitlab/alert_management/payload/generic_spec.rb30
-rw-r--r--spec/lib/gitlab/alerting/alert_spec.rb299
-rw-r--r--spec/lib/gitlab/danger/helper_spec.rb22
-rw-r--r--spec/mailers/emails/projects_spec.rb119
-rw-r--r--spec/models/concerns/issuable_spec.rb2
-rw-r--r--spec/models/concerns/reactive_caching_spec.rb11
-rw-r--r--spec/presenters/projects/prometheus/alert_presenter_spec.rb346
-rw-r--r--spec/services/notification_service_spec.rb21
-rw-r--r--spec/services/projects/alerting/notify_service_spec.rb20
-rw-r--r--spec/simplecov_env.rb3
-rw-r--r--spec/workers/incident_management/process_prometheus_alert_worker_spec.rb2
18 files changed, 250 insertions, 886 deletions
diff --git a/spec/controllers/projects/import/jira_controller_spec.rb b/spec/controllers/projects/import/jira_controller_spec.rb
index b82735a56b3..37a7fce0c23 100644
--- a/spec/controllers/projects/import/jira_controller_spec.rb
+++ b/spec/controllers/projects/import/jira_controller_spec.rb
@@ -12,7 +12,6 @@ RSpec.describe Projects::Import::JiraController do
def ensure_correct_config
sign_in(user)
project.add_maintainer(user)
- stub_feature_flags(jira_issue_import: true)
stub_jira_service_test
end
@@ -77,7 +76,6 @@ RSpec.describe Projects::Import::JiraController do
before do
sign_in(user)
project.add_maintainer(user)
- stub_feature_flags(jira_issue_import: true)
end
context 'when Jira service is not enabled for the project' do
diff --git a/spec/factories/alert_management/alerts.rb b/spec/factories/alert_management/alerts.rb
index d931947fff1..d0546657ccf 100644
--- a/spec/factories/alert_management/alerts.rb
+++ b/spec/factories/alert_management/alerts.rb
@@ -100,7 +100,7 @@ FactoryBot.define do
end
trait :prometheus do
- monitoring_tool { Gitlab::AlertManagement::AlertParams::MONITORING_TOOLS[:prometheus] }
+ monitoring_tool { Gitlab::AlertManagement::Payload::MONITORING_TOOLS[:prometheus] }
payload do
{
annotations: {
@@ -123,5 +123,17 @@ FactoryBot.define do
with_description
low
end
+
+ trait :from_payload do
+ after(:build) do |alert|
+ alert_params = ::Gitlab::AlertManagement::Payload.parse(
+ alert.project,
+ alert.payload,
+ monitoring_tool: alert.monitoring_tool
+ ).alert_params
+
+ alert.assign_attributes(alert_params)
+ end
+ end
end
end
diff --git a/spec/factories/alerting/alert.rb b/spec/factories/alerting/alert.rb
deleted file mode 100644
index 285bb14efa2..00000000000
--- a/spec/factories/alerting/alert.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# frozen_string_literal: true
-
-FactoryBot.define do
- factory :alerting_alert, class: 'Gitlab::Alerting::Alert' do
- project
- payload { {} }
-
- transient do
- metric_id { nil }
-
- after(:build) do |alert, evaluator|
- unless alert.payload.key?('startsAt')
- alert.payload['startsAt'] = Time.now.rfc3339
- end
-
- if metric_id = evaluator.metric_id
- alert.payload['labels'] ||= {}
- alert.payload['labels']['gitlab_alert_id'] = metric_id.to_s
- end
- end
- end
-
- skip_create
- end
-end
diff --git a/spec/frontend/packages/shared/components/__snapshots__/package_list_row_spec.js.snap b/spec/frontend/packages/shared/components/__snapshots__/package_list_row_spec.js.snap
index cf5451490eb..5faae5690db 100644
--- a/spec/frontend/packages/shared/components/__snapshots__/package_list_row_spec.js.snap
+++ b/spec/frontend/packages/shared/components/__snapshots__/package_list_row_spec.js.snap
@@ -52,27 +52,6 @@ exports[`packages_list_row renders 1`] = `
<!---->
<div
- class="gl-display-flex gl-align-items-center"
- >
- <gl-icon-stub
- class="gl-ml-3 gl-mr-2 gl-min-w-0"
- name="review-list"
- size="16"
- />
-
- <gl-link-stub
- class="gl-text-body gl-min-w-0"
- data-testid="packages-row-project"
- href="/foo/bar/baz"
- >
- <gl-truncate-stub
- position="end"
- text="foo/bar/baz"
- />
- </gl-link-stub>
- </div>
-
- <div
class="d-flex align-items-center"
data-testid="package-type"
>
@@ -86,6 +65,10 @@ exports[`packages_list_row renders 1`] = `
Maven
</span>
</div>
+
+ <package-path-stub
+ path="foo/bar/baz"
+ />
</div>
</div>
</div>
diff --git a/spec/frontend/packages/shared/components/package_list_row_spec.js b/spec/frontend/packages/shared/components/package_list_row_spec.js
index f4eabf7bb67..0d0ea4e2122 100644
--- a/spec/frontend/packages/shared/components/package_list_row_spec.js
+++ b/spec/frontend/packages/shared/components/package_list_row_spec.js
@@ -1,6 +1,7 @@
import { shallowMount } from '@vue/test-utils';
import PackagesListRow from '~/packages/shared/components/package_list_row.vue';
import PackageTags from '~/packages/shared/components/package_tags.vue';
+import PackagePath from '~/packages/shared/components/package_path.vue';
import ListItem from '~/vue_shared/components/registry/list_item.vue';
import { packageList } from '../../mock_data';
@@ -11,7 +12,7 @@ describe('packages_list_row', () => {
const [packageWithoutTags, packageWithTags] = packageList;
const findPackageTags = () => wrapper.find(PackageTags);
- const findProjectLink = () => wrapper.find('[data-testid="packages-row-project"]');
+ const findPackagePath = () => wrapper.find(PackagePath);
const findDeleteButton = () => wrapper.find('[data-testid="action-delete"]');
const findPackageType = () => wrapper.find('[data-testid="package-type"]');
@@ -63,8 +64,9 @@ describe('packages_list_row', () => {
mountComponent({ isGroup: true });
});
- it('has project field', () => {
- expect(findProjectLink().exists()).toBe(true);
+ it('has a package path component', () => {
+ expect(findPackagePath().exists()).toBe(true);
+ expect(findPackagePath().props()).toMatchObject({ path: 'foo/bar/baz' });
});
});
diff --git a/spec/frontend/packages/shared/components/package_path_spec.js b/spec/frontend/packages/shared/components/package_path_spec.js
new file mode 100644
index 00000000000..40d455ac77c
--- /dev/null
+++ b/spec/frontend/packages/shared/components/package_path_spec.js
@@ -0,0 +1,86 @@
+import { shallowMount } from '@vue/test-utils';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import PackagePath from '~/packages/shared/components/package_path.vue';
+
+describe('PackagePath', () => {
+ let wrapper;
+
+ const mountComponent = (propsData = { path: 'foo' }) => {
+ wrapper = shallowMount(PackagePath, {
+ propsData,
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
+ });
+ };
+
+ const BASE_ICON = 'base-icon';
+ const ROOT_LINK = 'root-link';
+ const ROOT_CHEVRON = 'root-chevron';
+ const ELLIPSIS_ICON = 'ellipsis-icon';
+ const ELLIPSIS_CHEVRON = 'ellipsis-chevron';
+ const LEAF_LINK = 'leaf-link';
+
+ const findItem = name => wrapper.find(`[data-testid="${name}"]`);
+ const findTooltip = w => getBinding(w.element, 'gl-tooltip');
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ describe.each`
+ path | rootUrl | shouldExist | shouldNotExist
+ ${'foo/bar'} | ${'/foo/bar'} | ${[]} | ${[ROOT_CHEVRON, ELLIPSIS_ICON, ELLIPSIS_CHEVRON, LEAF_LINK]}
+ ${'foo/bar/baz'} | ${'/foo/bar'} | ${[ROOT_CHEVRON, LEAF_LINK]} | ${[ELLIPSIS_ICON, ELLIPSIS_CHEVRON]}
+ ${'foo/bar/baz/baz2'} | ${'/foo/bar'} | ${[ROOT_CHEVRON, LEAF_LINK, ELLIPSIS_ICON, ELLIPSIS_CHEVRON]} | ${[]}
+ ${'foo/bar/baz/baz2/bar2'} | ${'/foo/bar'} | ${[ROOT_CHEVRON, LEAF_LINK, ELLIPSIS_ICON, ELLIPSIS_CHEVRON]} | ${[]}
+ `('given path $path', ({ path, shouldExist, shouldNotExist, rootUrl }) => {
+ const pathPieces = path.split('/').slice(1);
+ const hasTooltip = shouldExist.includes(ELLIPSIS_ICON);
+
+ beforeEach(() => {
+ mountComponent({ path });
+ });
+
+ it('should have a base icon', () => {
+ expect(findItem(BASE_ICON).exists()).toBe(true);
+ });
+
+ it('should have a root link', () => {
+ const root = findItem(ROOT_LINK);
+ expect(root.exists()).toBe(true);
+ expect(root.attributes('href')).toBe(rootUrl);
+ });
+
+ if (hasTooltip) {
+ it('should have a tooltip', () => {
+ const tooltip = findTooltip(findItem(ELLIPSIS_ICON));
+ expect(tooltip).toBeDefined();
+ expect(tooltip.value).toMatchObject({
+ title: path,
+ });
+ });
+ }
+
+ if (shouldExist.length) {
+ it.each(shouldExist)(`should have %s`, element => {
+ expect(findItem(element).exists()).toBe(true);
+ });
+ }
+
+ if (shouldNotExist.length) {
+ it.each(shouldNotExist)(`should not have %s`, element => {
+ expect(findItem(element).exists()).toBe(false);
+ });
+ }
+
+ if (shouldExist.includes(LEAF_LINK)) {
+ it('the last link should be the last piece of the path', () => {
+ const leaf = findItem(LEAF_LINK);
+ expect(leaf.attributes('href')).toBe(`/${path}`);
+ expect(leaf.text()).toBe(pathPieces[pathPieces.length - 1]);
+ });
+ }
+ });
+});
diff --git a/spec/lib/gitlab/alert_management/alert_params_spec.rb b/spec/lib/gitlab/alert_management/alert_params_spec.rb
deleted file mode 100644
index c3171be5e29..00000000000
--- a/spec/lib/gitlab/alert_management/alert_params_spec.rb
+++ /dev/null
@@ -1,101 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::AlertManagement::AlertParams do
- let_it_be(:project) { create(:project, :repository, :private) }
-
- describe '.from_generic_alert' do
- let(:started_at) { Time.current.change(usec: 0).rfc3339 }
- let(:default_payload) do
- {
- 'title' => 'Alert title',
- 'description' => 'Description',
- 'monitoring_tool' => 'Monitoring tool name',
- 'service' => 'Service',
- 'hosts' => ['gitlab.com'],
- 'start_time' => started_at,
- 'some' => { 'extra' => { 'payload' => 'here' } }
- }
- end
-
- let(:payload) { default_payload }
-
- subject { described_class.from_generic_alert(project: project, payload: payload) }
-
- it 'returns Alert compatible parameters' do
- is_expected.to eq(
- project_id: project.id,
- title: 'Alert title',
- description: 'Description',
- monitoring_tool: 'Monitoring tool name',
- service: 'Service',
- severity: 'critical',
- hosts: ['gitlab.com'],
- payload: payload,
- started_at: started_at,
- ended_at: nil,
- fingerprint: nil,
- environment: nil
- )
- end
-
- context 'when severity given' do
- let(:payload) { default_payload.merge(severity: 'low') }
-
- it 'returns Alert compatible parameters' do
- expect(subject[:severity]).to eq('low')
- end
- end
-
- context 'when there are no hosts in the payload' do
- let(:payload) { {} }
-
- it 'hosts param is an empty array' do
- expect(subject[:hosts]).to be_empty
- end
- end
- end
-
- describe '.from_prometheus_alert' do
- let(:payload) do
- {
- 'status' => 'firing',
- 'labels' => {
- 'alertname' => 'GitalyFileServerDown',
- 'channel' => 'gitaly',
- 'pager' => 'pagerduty',
- 'severity' => 's1'
- },
- 'annotations' => {
- 'description' => 'Alert description',
- 'runbook' => 'troubleshooting/gitaly-down.md',
- 'title' => 'Alert title'
- },
- 'startsAt' => '2020-04-27T10:10:22.265949279Z',
- 'endsAt' => '0001-01-01T00:00:00Z',
- 'generatorURL' => 'http://8d467bd4607a:9090/graph?g0.expr=vector%281%29&g0.tab=1',
- 'fingerprint' => 'b6ac4d42057c43c1'
- }
- end
-
- let(:parsed_alert) { Gitlab::Alerting::Alert.new(project: project, payload: payload) }
-
- subject { described_class.from_prometheus_alert(project: project, parsed_alert: parsed_alert) }
-
- it 'returns Alert-compatible params' do
- is_expected.to eq(
- project_id: project.id,
- title: 'Alert title',
- description: 'Alert description',
- monitoring_tool: 'Prometheus',
- payload: payload,
- started_at: parsed_alert.starts_at,
- ended_at: parsed_alert.ends_at,
- fingerprint: parsed_alert.gitlab_fingerprint,
- environment: parsed_alert.environment,
- prometheus_alert: parsed_alert.gitlab_alert
- )
- end
- end
-end
diff --git a/spec/lib/gitlab/alert_management/payload/generic_spec.rb b/spec/lib/gitlab/alert_management/payload/generic_spec.rb
index 538a822503e..3683dcd752f 100644
--- a/spec/lib/gitlab/alert_management/payload/generic_spec.rb
+++ b/spec/lib/gitlab/alert_management/payload/generic_spec.rb
@@ -86,4 +86,34 @@ RSpec.describe Gitlab::AlertManagement::Payload::Generic do
it_behaves_like 'parsable alert payload field', 'gitlab_environment_name'
end
+
+ describe '#description' do
+ subject { parsed_payload.description }
+
+ it_behaves_like 'parsable alert payload field', 'description'
+ end
+
+ describe '#ends_at' do
+ let(:current_time) { Time.current.change(usec: 0).utc }
+
+ subject { parsed_payload.ends_at }
+
+ around do |example|
+ Timecop.freeze(current_time) { example.run }
+ end
+
+ context 'without end_time' do
+ it { is_expected.to be_nil }
+ end
+
+ context "with end_time" do
+ let(:value) { 10.minutes.ago.change(usec: 0).utc }
+
+ before do
+ raw_payload['end_time'] = value.to_s
+ end
+
+ it { is_expected.to eq(value) }
+ end
+ end
end
diff --git a/spec/lib/gitlab/alerting/alert_spec.rb b/spec/lib/gitlab/alerting/alert_spec.rb
deleted file mode 100644
index b53b71e3f3e..00000000000
--- a/spec/lib/gitlab/alerting/alert_spec.rb
+++ /dev/null
@@ -1,299 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Alerting::Alert do
- let_it_be(:project) { create(:project) }
-
- let(:alert) { build(:alerting_alert, project: project, payload: payload) }
- let(:payload) { {} }
-
- shared_context 'gitlab alert' do
- let!(:gitlab_alert) { create(:prometheus_alert, project: project) }
- let(:gitlab_alert_id) { gitlab_alert.id }
-
- before do
- payload['labels'] = {
- 'gitlab_alert_id' => gitlab_alert.prometheus_metric_id.to_s,
- 'gitlab_prometheus_alert_id' => gitlab_alert_id
- }
- end
- end
-
- shared_context 'full query' do
- before do
- payload['generatorURL'] = 'http://localhost:9090/graph?g0.expr=vector%281%29'
- end
- end
-
- shared_examples 'invalid alert' do
- it 'is invalid' do
- expect(alert).not_to be_valid
- end
- end
-
- shared_examples 'parse payload' do |*pairs|
- context 'without payload' do
- it { is_expected.to be_nil }
- end
-
- pairs.each do |pair|
- context "with #{pair}" do
- let(:value) { 'some value' }
-
- before do
- section, name = pair.split('/')
- payload[section] = { name => value }
- end
-
- it { is_expected.to eq(value) }
- end
- end
- end
-
- describe '#gitlab_alert' do
- subject { alert.gitlab_alert }
-
- context 'without payload' do
- it { is_expected.to be_nil }
- end
-
- context 'with gitlab alert' do
- include_context 'gitlab alert'
-
- it { is_expected.to eq(gitlab_alert) }
- end
-
- context 'with unknown gitlab alert' do
- include_context 'gitlab alert' do
- let(:gitlab_alert_id) { 'unknown' }
- end
-
- it { is_expected.to be_nil }
- end
-
- context 'when two alerts with the same metric exist' do
- include_context 'gitlab alert'
-
- let!(:second_gitlab_alert) do
- create(:prometheus_alert,
- project: project,
- prometheus_metric_id: gitlab_alert.prometheus_metric_id
- )
- end
-
- context 'alert id given in params' do
- before do
- payload['labels'] = {
- 'gitlab_alert_id' => gitlab_alert.prometheus_metric_id.to_s,
- 'gitlab_prometheus_alert_id' => second_gitlab_alert.id
- }
- end
-
- it { is_expected.to eq(second_gitlab_alert) }
- end
-
- context 'metric id given in params' do
- # This tests the case when two alerts are found, as metric id
- # is not unique.
-
- # Note the metric id was incorrectly named as 'gitlab_alert_id'
- # in PrometheusAlert#to_param.
- before do
- payload['labels'] = { 'gitlab_alert_id' => gitlab_alert.prometheus_metric_id }
- end
-
- it { is_expected.to be_nil }
- end
- end
- end
-
- describe '#title' do
- subject { alert.title }
-
- it_behaves_like 'parse payload',
- 'annotations/title',
- 'annotations/summary',
- 'labels/alertname'
-
- context 'with gitlab alert' do
- include_context 'gitlab alert'
-
- context 'with annotations/title' do
- let(:value) { 'annotation title' }
-
- before do
- payload['annotations'] = { 'title' => value }
- end
-
- it { is_expected.to eq(gitlab_alert.title) }
- end
- end
- end
-
- describe '#description' do
- subject { alert.description }
-
- it_behaves_like 'parse payload', 'annotations/description'
- end
-
- describe '#annotations' do
- subject { alert.annotations }
-
- context 'without payload' do
- it { is_expected.to eq([]) }
- end
-
- context 'with payload' do
- before do
- payload['annotations'] = { 'foo' => 'value1', 'bar' => 'value2' }
- end
-
- it 'parses annotations' do
- expect(subject.size).to eq(2)
- expect(subject.map(&:label)).to eq(%w[foo bar])
- expect(subject.map(&:value)).to eq(%w[value1 value2])
- end
- end
- end
-
- describe '#environment' do
- subject { alert.environment }
-
- context 'without gitlab_alert' do
- it { is_expected.to be_nil }
- end
-
- context 'with gitlab alert' do
- include_context 'gitlab alert'
-
- it { is_expected.to eq(gitlab_alert.environment) }
- end
- end
-
- describe '#starts_at' do
- subject { alert.starts_at }
-
- context 'with empty startsAt' do
- before do
- payload['startsAt'] = nil
- end
-
- it { is_expected.to be_nil }
- end
-
- context 'with invalid startsAt' do
- before do
- payload['startsAt'] = 'invalid'
- end
-
- it { is_expected.to be_nil }
- end
-
- context 'with payload' do
- let(:time) { Time.current.change(usec: 0) }
-
- before do
- payload['startsAt'] = time.rfc3339
- end
-
- it { is_expected.to eq(time) }
- end
- end
-
- describe '#full_query' do
- using RSpec::Parameterized::TableSyntax
-
- subject { alert.full_query }
-
- where(:generator_url, :expected_query) do
- nil | nil
- 'http://localhost' | nil
- 'invalid url' | nil
- 'http://localhost:9090/graph?g1.expr=vector%281%29' | nil
- 'http://localhost:9090/graph?g0.expr=vector%281%29' | 'vector(1)'
- end
-
- with_them do
- before do
- payload['generatorURL'] = generator_url
- end
-
- it { is_expected.to eq(expected_query) }
- end
-
- context 'with gitlab alert' do
- include_context 'gitlab alert'
- include_context 'full query'
-
- it { is_expected.to eq(gitlab_alert.full_query) }
- end
- end
-
- describe '#y_label' do
- subject { alert.y_label }
-
- it_behaves_like 'parse payload', 'annotations/gitlab_y_label'
-
- context 'when y_label is not included in the payload' do
- it_behaves_like 'parse payload', 'annotations/title'
- end
- end
-
- describe '#alert_markdown' do
- subject { alert.alert_markdown }
-
- it_behaves_like 'parse payload', 'annotations/gitlab_incident_markdown'
- end
-
- describe '#gitlab_fingerprint' do
- subject { alert.gitlab_fingerprint }
-
- context 'when the alert is a GitLab managed alert' do
- include_context 'gitlab alert'
-
- it 'returns a fingerprint' do
- plain_fingerprint = [alert.metric_id, alert.starts_at_raw].join('/')
-
- is_expected.to eq(Digest::SHA1.hexdigest(plain_fingerprint))
- end
- end
-
- context 'when the alert is from self managed Prometheus' do
- include_context 'full query'
-
- it 'returns a fingerprint' do
- plain_fingerprint = [alert.starts_at_raw, alert.title, alert.full_query].join('/')
-
- is_expected.to eq(Digest::SHA1.hexdigest(plain_fingerprint))
- end
- end
- end
-
- describe '#valid?' do
- before do
- payload.update(
- 'annotations' => { 'title' => 'some title' },
- 'startsAt' => Time.current.rfc3339
- )
- end
-
- subject { alert }
-
- it { is_expected.to be_valid }
-
- context 'without project' do
- let(:project) { nil }
-
- it { is_expected.not_to be_valid }
- end
-
- context 'without starts_at' do
- before do
- payload['startsAt'] = nil
- end
-
- it { is_expected.not_to be_valid }
- end
- end
-end
diff --git a/spec/lib/gitlab/danger/helper_spec.rb b/spec/lib/gitlab/danger/helper_spec.rb
index c7d55c396ef..708e9a13aed 100644
--- a/spec/lib/gitlab/danger/helper_spec.rb
+++ b/spec/lib/gitlab/danger/helper_spec.rb
@@ -435,6 +435,28 @@ RSpec.describe Gitlab::Danger::Helper do
end
end
+ describe '#draft_mr?' do
+ it 'returns false when `gitlab_helper` is unavailable' do
+ expect(helper).to receive(:gitlab_helper).and_return(nil)
+
+ expect(helper).not_to be_draft_mr
+ end
+
+ it 'returns true for a draft MR' do
+ expect(fake_gitlab).to receive(:mr_json)
+ .and_return('title' => 'Draft: My MR title')
+
+ expect(helper).to be_draft_mr
+ end
+
+ it 'returns false for non draft MR' do
+ expect(fake_gitlab).to receive(:mr_json)
+ .and_return('title' => 'My MR title')
+
+ expect(helper).not_to be_draft_mr
+ end
+ end
+
describe '#cherry_pick_mr?' do
it 'returns false when `gitlab_helper` is unavailable' do
expect(helper).to receive(:gitlab_helper).and_return(nil)
diff --git a/spec/mailers/emails/projects_spec.rb b/spec/mailers/emails/projects_spec.rb
index 599f62a8113..aa5947bf68e 100644
--- a/spec/mailers/emails/projects_spec.rb
+++ b/spec/mailers/emails/projects_spec.rb
@@ -30,107 +30,118 @@ RSpec.describe Emails::Projects do
let_it_be(:user) { create(:user) }
describe '#prometheus_alert_fired_email' do
+ let(:default_title) { Gitlab::AlertManagement::Payload::Generic::DEFAULT_TITLE }
+ let(:payload) { { 'startsAt' => Time.now.rfc3339 } }
+ let(:alert_attributes) { build(:alert_management_alert, :from_payload, payload: payload, project: project).attributes }
+
subject do
- Notify.prometheus_alert_fired_email(project.id, user.id, alert_params)
+ Notify.prometheus_alert_fired_email(project.id, user.id, alert_attributes)
end
- let(:alert_params) do
- { 'startsAt' => Time.now.rfc3339 }
+ context 'missing required attributes' do
+ let(:alert_attributes) { build(:alert_management_alert, :prometheus, :from_payload, payload: payload, project: project).attributes }
+
+ it_behaves_like 'no email'
end
- context 'with a gitlab alert' do
- before do
- alert_params['labels'] = { 'gitlab_alert_id' => alert.prometheus_metric_id.to_s }
- end
+ context 'with minimum required attributes' do
+ let(:payload) { {} }
- let(:title) do
- "#{alert.title} #{alert.computed_operator} #{alert.threshold}"
- end
+ it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'it should not have Gmail Actions links'
+ it_behaves_like 'a user cannot unsubscribe through footer link'
- let(:metrics_url) do
- metrics_project_environment_url(project, environment)
+ it 'has expected subject' do
+ is_expected.to have_subject("#{project.name} | Alert: #{default_title}")
end
- let(:environment) { alert.environment }
+ it 'has expected content' do
+ is_expected.to have_body_text('An alert has been triggered')
+ is_expected.to have_body_text(project.full_path)
+ is_expected.not_to have_body_text('Description:')
+ is_expected.not_to have_body_text('Environment:')
+ is_expected.not_to have_body_text('Metric:')
+ end
+ end
- let!(:alert) { create(:prometheus_alert, project: project) }
+ context 'with description' do
+ let(:payload) { { 'description' => 'alert description' } }
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like 'a user cannot unsubscribe through footer link'
it 'has expected subject' do
- is_expected.to have_subject("#{project.name} | Alert: #{environment.name}: #{title} for 5 minutes")
+ is_expected.to have_subject("#{project.name} | Alert: #{default_title}")
end
it 'has expected content' do
is_expected.to have_body_text('An alert has been triggered')
is_expected.to have_body_text(project.full_path)
- is_expected.to have_body_text('Environment:')
- is_expected.to have_body_text(environment.name)
- is_expected.to have_body_text('Metric:')
- is_expected.to have_body_text(alert.full_query)
- is_expected.to have_body_text(metrics_url)
+ is_expected.to have_body_text('Description:')
+ is_expected.to have_body_text('alert description')
+ is_expected.not_to have_body_text('Environment:')
+ is_expected.not_to have_body_text('Metric:')
end
-
- it_behaves_like 'shows the incident issues url'
end
- context 'with no payload' do
- let(:alert_params) { {} }
+ context 'with environment' do
+ let_it_be(:environment) { create(:environment, project: project) }
+ let(:payload) { { 'gitlab_environment_name' => environment.name } }
+ let(:metrics_url) { metrics_project_environment_url(project, environment) }
- it_behaves_like 'no email'
- end
+ it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'it should not have Gmail Actions links'
+ it_behaves_like 'a user cannot unsubscribe through footer link'
- context 'with an unknown alert' do
- before do
- alert_params['labels'] = { 'gitlab_alert_id' => 'unknown' }
+ it 'has expected subject' do
+ is_expected.to have_subject("#{project.name} | Alert: #{environment.name}: #{default_title}")
end
- it_behaves_like 'no email'
+ it 'has expected content' do
+ is_expected.to have_body_text('An alert has been triggered')
+ is_expected.to have_body_text(project.full_path)
+ is_expected.to have_body_text('Environment:')
+ is_expected.to have_body_text(environment.name)
+ is_expected.not_to have_body_text('Description:')
+ is_expected.not_to have_body_text('Metric:')
+ end
end
- context 'with an external alert' do
- let(:title) { 'alert title' }
+ context 'with gitlab alerting rule' do
+ let_it_be(:prometheus_alert) { create(:prometheus_alert, project: project) }
+ let_it_be(:environment) { prometheus_alert.environment }
- let(:metrics_url) do
- metrics_project_environments_url(project)
- end
+ let(:alert_attributes) { build(:alert_management_alert, :prometheus, :from_payload, payload: payload, project: project).attributes }
+ let(:title) { "#{prometheus_alert.title} #{prometheus_alert.computed_operator} #{prometheus_alert.threshold}" }
+ let(:metrics_url) { metrics_project_environment_url(project, environment) }
before do
- alert_params['annotations'] = { 'title' => title }
- alert_params['generatorURL'] = 'http://localhost:9090/graph?g0.expr=vector%281%29&g0.tab=1'
+ payload['labels'] = {
+ 'gitlab_alert_id' => prometheus_alert.prometheus_metric_id,
+ 'alertname' => prometheus_alert.title
+ }
end
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like 'a user cannot unsubscribe through footer link'
+ it_behaves_like 'shows the incident issues url'
it 'has expected subject' do
- is_expected.to have_subject("#{project.name} | Alert: #{title}")
+ is_expected.to have_subject("#{project.name} | Alert: #{environment.name}: #{title} for 5 minutes")
end
it 'has expected content' do
is_expected.to have_body_text('An alert has been triggered')
is_expected.to have_body_text(project.full_path)
+ is_expected.to have_body_text('Environment:')
+ is_expected.to have_body_text(environment.name)
+ is_expected.to have_body_text('Metric:')
+ is_expected.to have_body_text(prometheus_alert.full_query)
+ is_expected.to have_body_text(metrics_url)
is_expected.not_to have_body_text('Description:')
- is_expected.not_to have_body_text('Environment:')
end
-
- context 'with annotated description' do
- let(:description) { 'description' }
-
- before do
- alert_params['annotations']['description'] = description
- end
-
- it 'shows the description' do
- is_expected.to have_body_text('Description:')
- is_expected.to have_body_text(description)
- end
- end
-
- it_behaves_like 'shows the incident issues url'
end
end
end
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index 1f335817d57..431865caf4c 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -824,7 +824,7 @@ RSpec.describe Issuable do
where(:issuable_type, :supports_time_tracking) do
:issue | true
- :incident | false
+ :incident | true
:merge_request | true
end
diff --git a/spec/models/concerns/reactive_caching_spec.rb b/spec/models/concerns/reactive_caching_spec.rb
index b12ad82920f..7e031bdd263 100644
--- a/spec/models/concerns/reactive_caching_spec.rb
+++ b/spec/models/concerns/reactive_caching_spec.rb
@@ -14,6 +14,7 @@ RSpec.describe ReactiveCaching, :use_clean_rails_memory_store_caching do
self.reactive_cache_lifetime = 5.minutes
self.reactive_cache_refresh_interval = 15.seconds
+ self.reactive_cache_work_type = :no_dependency
attr_reader :id
@@ -372,4 +373,14 @@ RSpec.describe ReactiveCaching, :use_clean_rails_memory_store_caching do
it { expect(subject.reactive_cache_hard_limit).to be_nil }
it { expect(subject.reactive_cache_worker_finder).to respond_to(:call) }
end
+
+ describe 'classes including this concern' do
+ it 'sets reactive_cache_work_type' do
+ classes = ObjectSpace.each_object(Class).select do |klass|
+ klass < described_class && klass.name
+ end
+
+ expect(classes).to all(have_attributes(reactive_cache_work_type: be_in(described_class::WORK_TYPE.keys)))
+ end
+ end
end
diff --git a/spec/presenters/projects/prometheus/alert_presenter_spec.rb b/spec/presenters/projects/prometheus/alert_presenter_spec.rb
deleted file mode 100644
index 98dba28829e..00000000000
--- a/spec/presenters/projects/prometheus/alert_presenter_spec.rb
+++ /dev/null
@@ -1,346 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Projects::Prometheus::AlertPresenter do
- include Gitlab::Routing.url_helpers
-
- let_it_be(:project, reload: true) { create(:project) }
-
- let(:presenter) { described_class.new(alert) }
- let(:payload) { {} }
- let(:alert) { create(:alerting_alert, project: project, payload: payload) }
-
- shared_context 'gitlab alert' do
- let(:gitlab_alert) { create(:prometheus_alert, project: project) }
- let(:metric_id) { gitlab_alert.prometheus_metric_id }
-
- let(:alert) do
- create(:alerting_alert, project: project, metric_id: metric_id, payload: payload)
- end
- end
-
- describe '#project_full_path' do
- subject { presenter.project_full_path }
-
- it { is_expected.to eq(project.full_path) }
- end
-
- describe '#start_time' do
- subject { presenter.start_time }
-
- let(:starts_at) { '2020-10-31T14:02:04Z' }
-
- before do
- payload['startsAt'] = starts_at
- end
-
- context 'with valid utc datetime' do
- it { is_expected.to eq('31 October 2020, 2:02PM (UTC)') }
-
- context 'with admin time zone not UTC' do
- before do
- allow(Time).to receive(:zone).and_return(ActiveSupport::TimeZone.new('Perth'))
- end
-
- it { is_expected.to eq('31 October 2020, 2:02PM (UTC)') }
- end
- end
-
- context 'with invalid datetime' do
- let(:starts_at) { 'invalid' }
-
- it { is_expected.to be_nil }
- end
- end
-
- describe '#issue_summary_markdown' do
- let(:markdown_line_break) { ' ' }
-
- subject { presenter.issue_summary_markdown }
-
- context 'without default payload' do
- it do
- is_expected.to eq(
- <<~MARKDOWN.chomp
- **Start time:** #{presenter.start_time}
-
- MARKDOWN
- )
- end
- end
-
- context 'with optional attributes' do
- before do
- payload['annotations'] = {
- 'title' => 'Alert Title',
- 'foo' => 'value1',
- 'bar' => 'value2',
- 'description' => 'Alert Description',
- 'monitoring_tool' => 'monitoring_tool_name',
- 'service' => 'service_name',
- 'hosts' => ['http://localhost:3000', 'http://localhost:3001']
- }
- payload['generatorURL'] = 'http://host?g0.expr=query'
- end
-
- it do
- is_expected.to eq(
- <<~MARKDOWN.chomp
- **Start time:** #{presenter.start_time}#{markdown_line_break}
- **full_query:** `query`#{markdown_line_break}
- **Service:** service_name#{markdown_line_break}
- **Monitoring tool:** monitoring_tool_name#{markdown_line_break}
- **Hosts:** http://localhost:3000 http://localhost:3001
-
- MARKDOWN
- )
- end
- end
-
- context 'when hosts is a string' do
- before do
- payload['annotations'] = { 'hosts' => 'http://localhost:3000' }
- end
-
- it do
- is_expected.to eq(
- <<~MARKDOWN.chomp
- **Start time:** #{presenter.start_time}#{markdown_line_break}
- **Hosts:** http://localhost:3000
-
- MARKDOWN
- )
- end
- end
-
- context 'with embedded metrics' do
- let(:starts_at) { '2018-03-12T09:06:00Z' }
-
- shared_examples_for 'markdown with metrics embed' do
- let(:embed_regex) { /\n\[\]\(#{Regexp.quote(presenter.metrics_dashboard_url)}\)\z/ }
-
- context 'without a starting time available' do
- around do |example|
- Timecop.freeze(starts_at) { example.run }
- end
-
- before do
- payload.delete('startsAt')
- end
-
- it { is_expected.to match(embed_regex) }
- end
-
- context 'with a starting time available' do
- it { is_expected.to match(embed_regex) }
- end
- end
-
- context 'for gitlab-managed prometheus alerts' do
- include_context 'gitlab-managed prometheus alert attributes'
-
- let(:alert) do
- create(:alerting_alert, project: project, metric_id: prometheus_metric_id, payload: payload)
- end
-
- it_behaves_like 'markdown with metrics embed'
- end
-
- context 'for alerts from a self-managed prometheus' do
- include_context 'self-managed prometheus alert attributes'
-
- it_behaves_like 'markdown with metrics embed'
-
- context 'without y_label' do
- let(:y_label) { title }
-
- before do
- payload['annotations'].delete('gitlab_y_label')
- end
-
- it_behaves_like 'markdown with metrics embed'
- end
-
- context 'when not enough information is present for an embed' do
- shared_examples_for 'does not include an embed' do
- it { is_expected.not_to match(/\[\]\(.+\)/) }
- end
-
- context 'without title' do
- before do
- payload['annotations'].delete('title')
- end
-
- it_behaves_like 'does not include an embed'
- end
-
- context 'without environment' do
- before do
- payload['labels'].delete('gitlab_environment_name')
- end
-
- it_behaves_like 'does not include an embed'
- end
-
- context 'without full_query' do
- before do
- payload.delete('generatorURL')
- end
-
- it_behaves_like 'does not include an embed'
- end
- end
- end
- end
- end
-
- describe '#show_performance_dashboard_link?' do
- subject { presenter.show_performance_dashboard_link? }
-
- it { is_expected.to be_falsey }
-
- context 'with gitlab alert' do
- include_context 'gitlab alert'
-
- it { is_expected.to eq(true) }
- end
- end
-
- describe '#show_incident_issues_link?' do
- subject { presenter.show_incident_issues_link? }
-
- it { is_expected.to be_falsey }
-
- context 'create issue setting enabled' do
- before do
- create(:project_incident_management_setting, project: project, create_issue: true)
- end
-
- it { is_expected.to eq(true) }
- end
- end
-
- describe '#details_url' do
- subject { presenter.details_url }
-
- it { is_expected.to eq(nil) }
-
- context 'alert management alert present' do
- let_it_be(:am_alert) { create(:alert_management_alert, project: project) }
- let(:alert) { create(:alerting_alert, project: project, payload: payload, am_alert: am_alert) }
-
- it { is_expected.to eq("http://localhost/#{project.full_path}/-/alert_management/#{am_alert.iid}/details") }
- end
- end
-
- context 'with gitlab alert' do
- include_context 'gitlab alert'
-
- describe '#full_title' do
- let(:query_title) do
- "#{gitlab_alert.title} #{gitlab_alert.computed_operator} #{gitlab_alert.threshold} for 5 minutes"
- end
-
- let(:expected_subject) do
- "#{alert.environment.name}: #{query_title}"
- end
-
- subject { presenter.full_title }
-
- it { is_expected.to eq(expected_subject) }
- end
-
- describe '#metric_query' do
- subject { presenter.metric_query }
-
- it { is_expected.to eq(gitlab_alert.full_query) }
- end
-
- describe '#environment_name' do
- subject { presenter.environment_name }
-
- it { is_expected.to eq(alert.environment.name) }
- end
-
- describe '#performance_dashboard_link' do
- let(:expected_link) { metrics_project_environment_url(project, alert.environment) }
-
- subject { presenter.performance_dashboard_link }
-
- it { is_expected.to eq(expected_link) }
- end
-
- describe '#incident_issues_link' do
- let(:expected_link) { project_issues_url(project, label_name: described_class::INCIDENT_LABEL_NAME) }
-
- subject { presenter.incident_issues_link }
-
- it { is_expected.to eq(expected_link) }
- end
- end
-
- context 'without gitlab alert' do
- describe '#full_title' do
- subject { presenter.full_title }
-
- context 'with title' do
- let(:title) { 'some title' }
-
- before do
- expect(alert).to receive(:title).and_return(title)
- end
-
- it { is_expected.to eq(title) }
- end
-
- context 'without title' do
- it { is_expected.to eq('') }
- end
- end
-
- describe '#metric_query' do
- subject { presenter.metric_query }
-
- it { is_expected.to be_nil }
- end
-
- describe '#environment_name' do
- subject { presenter.environment_name }
-
- it { is_expected.to be_nil }
- end
-
- describe '#performance_dashboard_link' do
- let(:expected_link) { metrics_project_environments_url(project) }
-
- subject { presenter.performance_dashboard_link }
-
- it { is_expected.to eq(expected_link) }
- end
- end
-
- describe '#metrics_dashboard_url' do
- subject { presenter.metrics_dashboard_url }
-
- context 'for a non-prometheus alert' do
- it { is_expected.to be_nil }
- end
-
- context 'for a self-managed prometheus alert' do
- include_context 'self-managed prometheus alert attributes'
-
- let(:prometheus_payload) { payload }
-
- it { is_expected.to eq(dashboard_url_for_alert) }
- end
-
- context 'for a gitlab-managed prometheus alert' do
- include_context 'gitlab-managed prometheus alert attributes'
-
- let(:prometheus_payload) { payload }
-
- it { is_expected.to eq(dashboard_url_for_alert) }
- end
- end
-end
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index af988381017..473a06c4c8c 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -3082,32 +3082,25 @@ RSpec.describe NotificationService, :mailer do
describe '#prometheus_alerts_fired' do
let!(:project) { create(:project) }
- let!(:prometheus_alert) { create(:prometheus_alert, project: project) }
let!(:master) { create(:user) }
let!(:developer) { create(:user) }
+ let(:alert_attributes) { build(:alert_management_alert, project: project).attributes }
before do
project.add_maintainer(master)
end
it 'sends the email to owners and masters' do
- expect(Notify).to receive(:prometheus_alert_fired_email).with(project.id, master.id, prometheus_alert).and_call_original
- expect(Notify).to receive(:prometheus_alert_fired_email).with(project.id, project.owner.id, prometheus_alert).and_call_original
- expect(Notify).not_to receive(:prometheus_alert_fired_email).with(project.id, developer.id, prometheus_alert)
+ expect(Notify).to receive(:prometheus_alert_fired_email).with(project.id, master.id, alert_attributes).and_call_original
+ expect(Notify).to receive(:prometheus_alert_fired_email).with(project.id, project.owner.id, alert_attributes).and_call_original
+ expect(Notify).not_to receive(:prometheus_alert_fired_email).with(project.id, developer.id, alert_attributes)
- subject.prometheus_alerts_fired(prometheus_alert.project, [prometheus_alert])
+ subject.prometheus_alerts_fired(project, [alert_attributes])
end
it_behaves_like 'project emails are disabled' do
- before do
- allow_next_instance_of(::Gitlab::Alerting::Alert) do |instance|
- allow(instance).to receive(:valid?).and_return(true)
- end
- end
-
- let(:alert_params) { { 'labels' => { 'gitlab_alert_id' => 'unknown' } } }
- let(:notification_target) { prometheus_alert.project }
- let(:notification_trigger) { subject.prometheus_alerts_fired(prometheus_alert.project, [alert_params]) }
+ let(:notification_target) { project }
+ let(:notification_trigger) { subject.prometheus_alerts_fired(project, [alert_attributes]) }
around do |example|
perform_enqueued_jobs { example.run }
diff --git a/spec/services/projects/alerting/notify_service_spec.rb b/spec/services/projects/alerting/notify_service_spec.rb
index 68764990886..24741db40bc 100644
--- a/spec/services/projects/alerting/notify_service_spec.rb
+++ b/spec/services/projects/alerting/notify_service_spec.rb
@@ -197,11 +197,10 @@ RSpec.describe Projects::Alerting::NotifyService do
end
context 'with overlong payload' do
- let(:payload_raw) do
- {
- title: 'a' * Gitlab::Utils::DeepSize::DEFAULT_MAX_SIZE,
- start_time: starts_at.rfc3339
- }
+ let(:deep_size_object) { instance_double(Gitlab::Utils::DeepSize, valid?: false) }
+
+ before do
+ allow(Gitlab::Utils::DeepSize).to receive(:new).and_return(deep_size_object)
end
it_behaves_like 'does not process incident issues due to error', http_status: :bad_request
@@ -215,17 +214,6 @@ RSpec.describe Projects::Alerting::NotifyService do
it_behaves_like 'processes incident issues'
- context 'with an invalid payload' do
- before do
- allow(Gitlab::Alerting::NotificationPayloadParser)
- .to receive(:call)
- .and_raise(Gitlab::Alerting::NotificationPayloadParser::BadPayloadError)
- end
-
- it_behaves_like 'does not process incident issues due to error', http_status: :bad_request
- it_behaves_like 'does not an create alert management alert'
- end
-
context 'when alert already exists' do
let(:fingerprint_sha) { Digest::SHA1.hexdigest(fingerprint) }
let!(:alert) { create(:alert_management_alert, project: project, fingerprint: fingerprint_sha) }
diff --git a/spec/simplecov_env.rb b/spec/simplecov_env.rb
index 17b76205d9e..617a45ae449 100644
--- a/spec/simplecov_env.rb
+++ b/spec/simplecov_env.rb
@@ -2,7 +2,6 @@
require 'simplecov'
require 'simplecov-cobertura'
-require 'active_support/core_ext/numeric/time'
require_relative '../lib/gitlab/utils'
module SimpleCovEnv
@@ -75,7 +74,7 @@ module SimpleCovEnv
add_group 'Libraries', %w[/lib /ee/lib]
add_group 'Tooling', %w[/haml_lint /rubocop /tooling]
- merge_timeout 365.days
+ merge_timeout 365 * 24 * 3600
end
end
end
diff --git a/spec/workers/incident_management/process_prometheus_alert_worker_spec.rb b/spec/workers/incident_management/process_prometheus_alert_worker_spec.rb
index c294892a66f..2ca4193aa72 100644
--- a/spec/workers/incident_management/process_prometheus_alert_worker_spec.rb
+++ b/spec/workers/incident_management/process_prometheus_alert_worker_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe IncidentManagement::ProcessPrometheusAlertWorker do
describe '#perform' do
let_it_be(:project) { create(:project) }
let_it_be(:prometheus_alert) { create(:prometheus_alert, project: project) }
- let(:payload_key) { Gitlab::Alerting::Alert.new(project: project, payload: alert_params).gitlab_fingerprint }
+ let(:payload_key) { Gitlab::AlertManagement::Payload::Prometheus.new(project: project, payload: alert_params).gitlab_fingerprint }
let!(:prometheus_alert_event) { create(:prometheus_alert_event, prometheus_alert: prometheus_alert, payload_key: payload_key) }
let!(:settings) { create(:project_incident_management_setting, project: project, create_issue: true) }