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
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/vue_shared/components/members/action_buttons/user_action_buttons.vue11
-rw-r--r--app/assets/javascripts/vue_shared/components/members/table/expiration_datepicker.vue9
-rw-r--r--app/assets/javascripts/vue_shared/components/members/table/members_table.vue4
-rw-r--r--app/assets/javascripts/vue_shared/components/members/table/role_dropdown.vue17
-rw-r--r--app/assets/stylesheets/pages/members.scss2
-rw-r--r--app/views/search/_filter.html.haml4
-rw-r--r--changelogs/unreleased/270412-license-error-in-template.yml5
-rw-r--r--changelogs/unreleased/bjk-http_requests_total_status_matrix.yml5
-rw-r--r--config/initializers/7_prometheus_metrics.rb2
-rw-r--r--lib/gitlab/ci/templates/Security/API-Fuzzing.gitlab-ci.yml11
-rw-r--r--lib/gitlab/metrics/requests_rack_middleware.rb44
-rw-r--r--locale/gitlab.pot6
-rw-r--r--spec/features/search/user_searches_for_code_spec.rb5
-rw-r--r--spec/features/search/user_searches_for_issues_spec.rb5
-rw-r--r--spec/features/search/user_searches_for_merge_requests_spec.rb5
-rw-r--r--spec/features/search/user_searches_for_milestones_spec.rb5
-rw-r--r--spec/features/search/user_searches_for_wiki_pages_spec.rb5
-rw-r--r--spec/features/search/user_uses_search_filters_spec.rb6
-rw-r--r--spec/frontend/vue_shared/components/members/table/role_dropdown_spec.js1
-rw-r--r--spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb88
20 files changed, 153 insertions, 87 deletions
diff --git a/app/assets/javascripts/vue_shared/components/members/action_buttons/user_action_buttons.vue b/app/assets/javascripts/vue_shared/components/members/action_buttons/user_action_buttons.vue
index 8fa3d439fc1..484dbb8fef5 100644
--- a/app/assets/javascripts/vue_shared/components/members/action_buttons/user_action_buttons.vue
+++ b/app/assets/javascripts/vue_shared/components/members/action_buttons/user_action_buttons.vue
@@ -6,7 +6,13 @@ import { s__, sprintf } from '~/locale';
export default {
name: 'UserActionButtons',
- components: { ActionButtonGroup, RemoveMemberButton, LeaveButton },
+ components: {
+ ActionButtonGroup,
+ RemoveMemberButton,
+ LeaveButton,
+ LdapOverrideButton: () =>
+ import('ee_component/vue_shared/components/members/ldap/ldap_override_button.vue'),
+ },
props: {
member: {
type: Object,
@@ -57,5 +63,8 @@ export default {
:title="s__('Member|Remove member')"
/>
</div>
+ <div v-else-if="permissions.canOverride && !member.isOverridden" class="gl-px-1">
+ <ldap-override-button :member="member" />
+ </div>
</action-button-group>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/table/expiration_datepicker.vue b/app/assets/javascripts/vue_shared/components/members/table/expiration_datepicker.vue
index e72093b6c9e..0a8af81c1d1 100644
--- a/app/assets/javascripts/vue_shared/components/members/table/expiration_datepicker.vue
+++ b/app/assets/javascripts/vue_shared/components/members/table/expiration_datepicker.vue
@@ -32,6 +32,13 @@ export default {
return getDateInFuture(beginningOfToday, 1);
},
+ disabled() {
+ return (
+ this.busy ||
+ !this.permissions.canUpdate ||
+ (this.permissions.canOverride && !this.member.isOverridden)
+ );
+ },
},
mounted() {
if (this.member.expiresAt) {
@@ -85,7 +92,7 @@ export default {
:container="null"
:min-date="minDate"
:placeholder="__('Expiration date')"
- :disabled="!permissions.canUpdate || busy"
+ :disabled="disabled"
@input="handleInput"
@clear="handleClear"
/>
diff --git a/app/assets/javascripts/vue_shared/components/members/table/members_table.vue b/app/assets/javascripts/vue_shared/components/members/table/members_table.vue
index 5a5b42e7952..7f6fe1ee250 100644
--- a/app/assets/javascripts/vue_shared/components/members/table/members_table.vue
+++ b/app/assets/javascripts/vue_shared/components/members/table/members_table.vue
@@ -1,6 +1,7 @@
<script>
import { mapState } from 'vuex';
import { GlTable, GlBadge } from '@gitlab/ui';
+import MembersTableCell from 'ee_else_ce/vue_shared/components/members/table/members_table_cell.vue';
import { FIELDS } from '../constants';
import initUserPopovers from '~/user_popovers';
import MemberAvatar from './member_avatar.vue';
@@ -8,7 +9,6 @@ import MemberSource from './member_source.vue';
import CreatedAt from './created_at.vue';
import ExpiresAt from './expires_at.vue';
import MemberActionButtons from './member_action_buttons.vue';
-import MembersTableCell from './members_table_cell.vue';
import RoleDropdown from './role_dropdown.vue';
import RemoveGroupLinkModal from '../modals/remove_group_link_modal.vue';
import ExpirationDatepicker from './expiration_datepicker.vue';
@@ -91,7 +91,7 @@ export default {
<template #cell(maxRole)="{ item: member }">
<members-table-cell #default="{ permissions }" :member="member">
- <role-dropdown v-if="permissions.canUpdate" :member="member" />
+ <role-dropdown v-if="permissions.canUpdate" :permissions="permissions" :member="member" />
<gl-badge v-else>{{ member.accessLevel.stringValue }}</gl-badge>
</members-table-cell>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/table/role_dropdown.vue b/app/assets/javascripts/vue_shared/components/members/table/role_dropdown.vue
index 2b40ccc3a9d..42a5ca1b3c9 100644
--- a/app/assets/javascripts/vue_shared/components/members/table/role_dropdown.vue
+++ b/app/assets/javascripts/vue_shared/components/members/table/role_dropdown.vue
@@ -9,12 +9,18 @@ export default {
components: {
GlDropdown,
GlDropdownItem,
+ LdapDropdownItem: () =>
+ import('ee_component/vue_shared/components/members/ldap/ldap_dropdown_item.vue'),
},
props: {
member: {
type: Object,
required: true,
},
+ permissions: {
+ type: Object,
+ required: true,
+ },
},
data() {
return {
@@ -22,6 +28,11 @@ export default {
busy: false,
};
},
+ computed: {
+ disabled() {
+ return this.busy || (this.permissions.canOverride && !this.member.isOverridden);
+ },
+ },
mounted() {
this.isDesktop = bp.isDesktop();
},
@@ -55,7 +66,7 @@ export default {
:right="!isDesktop"
:text="member.accessLevel.stringValue"
:header-text="__('Change permissions')"
- :disabled="busy"
+ :disabled="disabled"
>
<gl-dropdown-item
v-for="(value, name) in member.validRoles"
@@ -66,5 +77,9 @@ export default {
>
{{ name }}
</gl-dropdown-item>
+ <ldap-dropdown-item
+ v-if="permissions.canOverride && member.isOverridden"
+ :member-id="member.id"
+ />
</gl-dropdown>
</template>
diff --git a/app/assets/stylesheets/pages/members.scss b/app/assets/stylesheets/pages/members.scss
index 135ab5ed7a1..a8b489f1273 100644
--- a/app/assets/stylesheets/pages/members.scss
+++ b/app/assets/stylesheets/pages/members.scss
@@ -225,7 +225,7 @@
}
.col-actions {
- width: px-to-rem(50px);
+ width: px-to-rem(65px);
}
}
diff --git a/app/views/search/_filter.html.haml b/app/views/search/_filter.html.haml
index e7febd4638b..6e8e7d8fd1f 100644
--- a/app/views/search/_filter.html.haml
+++ b/app/views/search/_filter.html.haml
@@ -17,10 +17,10 @@
= dropdown_content
= dropdown_loading
-.dropdown.project-filter.form-group.mb-lg-0.mx-lg-1
+.dropdown.form-group.mb-lg-0.mx-lg-1{ data: { testid: "project-filter" } }
%label.d-block{ for: "dashboard_search_project" }
= _("Project")
- %button.dropdown-menu-toggle.gl-display-inline-flex.js-search-project-dropdown.gl-mt-0{ type: "button", id: "dashboard_search_project", data: { toggle: "dropdown", target: '.project-filter' } }
+ %button.dropdown-menu-toggle.gl-display-inline-flex.js-search-project-dropdown.gl-mt-0{ type: "button", id: "dashboard_search_project", data: { toggle: "dropdown" } }
%span.dropdown-toggle-text.gl-flex-grow-1.str-truncated-100
= @project&.full_name || _("Any")
- if @project.present?
diff --git a/changelogs/unreleased/270412-license-error-in-template.yml b/changelogs/unreleased/270412-license-error-in-template.yml
new file mode 100644
index 00000000000..e3a7b9daa36
--- /dev/null
+++ b/changelogs/unreleased/270412-license-error-in-template.yml
@@ -0,0 +1,5 @@
+---
+title: Show error in pipeline when API Fuzzing not licensed
+merge_request: 46064
+author:
+type: changed
diff --git a/changelogs/unreleased/bjk-http_requests_total_status_matrix.yml b/changelogs/unreleased/bjk-http_requests_total_status_matrix.yml
new file mode 100644
index 00000000000..979e6f507a0
--- /dev/null
+++ b/changelogs/unreleased/bjk-http_requests_total_status_matrix.yml
@@ -0,0 +1,5 @@
+---
+title: Make sure the http_requests_total and http_request_duration_seconds metrics are not empty on application start
+merge_request: 45755
+author:
+type: fixed
diff --git a/config/initializers/7_prometheus_metrics.rb b/config/initializers/7_prometheus_metrics.rb
index dbaebc83658..65ff6b656b9 100644
--- a/config/initializers/7_prometheus_metrics.rb
+++ b/config/initializers/7_prometheus_metrics.rb
@@ -70,7 +70,7 @@ if !Rails.env.test? && Gitlab::Metrics.prometheus_metrics_enabled?
Gitlab::Metrics.gauge(:deployments, 'GitLab Version', {}, :max).set({ version: Gitlab::VERSION }, 1)
unless Gitlab::Runtime.sidekiq?
- Gitlab::Metrics::RequestsRackMiddleware.initialize_http_request_duration_seconds
+ Gitlab::Metrics::RequestsRackMiddleware.initialize_metrics
end
rescue IOError => e
Gitlab::ErrorTracking.track_exception(e)
diff --git a/lib/gitlab/ci/templates/Security/API-Fuzzing.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/API-Fuzzing.gitlab-ci.yml
index 6eab3557024..68ea302261f 100644
--- a/lib/gitlab/ci/templates/Security/API-Fuzzing.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/API-Fuzzing.gitlab-ci.yml
@@ -26,6 +26,17 @@ variables:
FUZZAPI_IMAGE: registry.gitlab.com/gitlab-org/security-products/analyzers/api-fuzzing:${FUZZAPI_VERSION}-engine
#
+apifuzzer_fuzz_unlicensed:
+ stage: fuzz
+ allow_failure: true
+ rules:
+ - if: '$GITLAB_FEATURES !~ /\bapi_fuzzing\b/ && $API_FUZZING_DISABLED == null'
+ - when: never
+ script:
+ - |
+ echo "Error: Your GitLab project is not licensed for API Fuzzing."
+ - exit 1
+
apifuzzer_fuzz:
stage: fuzz
image:
diff --git a/lib/gitlab/metrics/requests_rack_middleware.rb b/lib/gitlab/metrics/requests_rack_middleware.rb
index bb7ecb6128c..8b2aa4d29d7 100644
--- a/lib/gitlab/metrics/requests_rack_middleware.rb
+++ b/lib/gitlab/metrics/requests_rack_middleware.rb
@@ -3,7 +3,15 @@
module Gitlab
module Metrics
class RequestsRackMiddleware
- HTTP_METHODS = %w(delete get head options patch post put).to_set.freeze
+ HTTP_METHODS = {
+ "delete" => %w(200 202 204 303 400 401 403 404 500 503),
+ "get" => %w(200 204 301 302 303 304 307 400 401 403 404 410 422 429 500 503),
+ "head" => %w(200 204 301 302 303 401 403 404 410 500),
+ "options" => %w(200 404),
+ "patch" => %w(200 202 204 400 403 404 409 416 500),
+ "post" => %w(200 201 202 204 301 302 303 304 400 401 403 404 406 409 410 412 422 429 500 503),
+ "put" => %w(200 202 204 400 401 403 404 405 406 409 410 422 500)
+ }.freeze
HEALTH_ENDPOINT = /^\/-\/(liveness|readiness|health|metrics)\/?$/.freeze
@@ -14,8 +22,8 @@ module Gitlab
@app = app
end
- def self.http_request_total
- @http_request_total ||= ::Gitlab::Metrics.counter(:http_requests_total, 'Request count')
+ def self.http_requests_total
+ @http_requests_total ||= ::Gitlab::Metrics.counter(:http_requests_total, 'Request count')
end
def self.rack_uncaught_errors_count
@@ -31,15 +39,31 @@ module Gitlab
@http_health_requests_total ||= ::Gitlab::Metrics.counter(:http_health_requests_total, 'Health endpoint request count')
end
- def self.initialize_http_request_duration_seconds
- HTTP_METHODS.each do |method|
+ def self.initialize_metrics
+ # This initialization is done to avoid gaps in scraped metrics after
+ # restarts. It makes sure all counters/histograms are available at
+ # process start.
+ #
+ # For example `rate(http_requests_total{status="500"}[1m])` would return
+ # no data until the first 500 error would occur.
+
+ # The list of feature categories is currently not needed by the application
+ # anywhere else. So no need to keep these in memory forever.
+ # Doing it here, means we're only reading the file on boot.
+ feature_categories = YAML.load_file(Rails.root.join('config', 'feature_categories.yml')).map(&:strip).uniq << FEATURE_CATEGORY_DEFAULT
+
+ HTTP_METHODS.each do |method, statuses|
http_request_duration_seconds.get({ method: method })
+
+ statuses.product(feature_categories) do |status, feature_category|
+ http_requests_total.get({ method: method, status: status, feature_category: feature_category })
+ end
end
end
def call(env)
method = env['REQUEST_METHOD'].downcase
- method = 'INVALID' unless HTTP_METHODS.include?(method)
+ method = 'INVALID' unless HTTP_METHODS.key?(method)
started = Time.now.to_f
health_endpoint = health_endpoint?(env['PATH_INFO'])
status = 'undefined'
@@ -61,9 +85,13 @@ module Gitlab
raise
ensure
if health_endpoint
- RequestsRackMiddleware.http_health_requests_total.increment(status: status, method: method)
+ RequestsRackMiddleware.http_health_requests_total.increment(status: status.to_s, method: method)
else
- RequestsRackMiddleware.http_request_total.increment(status: status, method: method, feature_category: feature_category.presence || FEATURE_CATEGORY_DEFAULT)
+ RequestsRackMiddleware.http_requests_total.increment(
+ status: status.to_s,
+ method: method,
+ feature_category: feature_category.presence || FEATURE_CATEGORY_DEFAULT
+ )
end
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 5b9d9ee4a3b..49955728c10 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -16414,6 +16414,12 @@ msgstr ""
msgid "Members|Remove group"
msgstr ""
+msgid "Members|Revert to LDAP group sync settings"
+msgstr ""
+
+msgid "Members|Reverted to LDAP group sync settings."
+msgstr ""
+
msgid "Members|Role updated successfully."
msgstr ""
diff --git a/spec/features/search/user_searches_for_code_spec.rb b/spec/features/search/user_searches_for_code_spec.rb
index a88043c98ac..f761bd30baf 100644
--- a/spec/features/search/user_searches_for_code_spec.rb
+++ b/spec/features/search/user_searches_for_code_spec.rb
@@ -28,10 +28,7 @@ RSpec.describe 'User searches for code' do
before do
visit(search_path)
find('.js-search-project-dropdown').click
-
- page.within('.project-filter') do
- click_link(project.full_name)
- end
+ find('[data-testid="project-filter"]').click_link(project.full_name)
end
include_examples 'top right search form'
diff --git a/spec/features/search/user_searches_for_issues_spec.rb b/spec/features/search/user_searches_for_issues_spec.rb
index 35d5722f708..e2ae2738d2f 100644
--- a/spec/features/search/user_searches_for_issues_spec.rb
+++ b/spec/features/search/user_searches_for_issues_spec.rb
@@ -86,10 +86,7 @@ RSpec.describe 'User searches for issues', :js do
context 'when on a project page' do
it 'finds an issue' do
find('.js-search-project-dropdown').click
-
- page.within('.project-filter') do
- click_link(project.full_name)
- end
+ find('[data-testid="project-filter"]').click_link(project.full_name)
search_for_issue(issue1.title)
diff --git a/spec/features/search/user_searches_for_merge_requests_spec.rb b/spec/features/search/user_searches_for_merge_requests_spec.rb
index 40583664958..6f8f6303b66 100644
--- a/spec/features/search/user_searches_for_merge_requests_spec.rb
+++ b/spec/features/search/user_searches_for_merge_requests_spec.rb
@@ -31,10 +31,7 @@ RSpec.describe 'User searches for merge requests', :js do
context 'when on a project page' do
it 'finds a merge request' do
find('.js-search-project-dropdown').click
-
- page.within('.project-filter') do
- click_link(project.full_name)
- end
+ find('[data-testid="project-filter"]').click_link(project.full_name)
fill_in('dashboard_search', with: merge_request1.title)
find('.btn-search').click
diff --git a/spec/features/search/user_searches_for_milestones_spec.rb b/spec/features/search/user_searches_for_milestones_spec.rb
index 64e756db180..1a2227db214 100644
--- a/spec/features/search/user_searches_for_milestones_spec.rb
+++ b/spec/features/search/user_searches_for_milestones_spec.rb
@@ -31,10 +31,7 @@ RSpec.describe 'User searches for milestones', :js do
context 'when on a project page' do
it 'finds a milestone' do
find('.js-search-project-dropdown').click
-
- page.within('.project-filter') do
- click_link(project.full_name)
- end
+ find('[data-testid="project-filter"]').click_link(project.full_name)
fill_in('dashboard_search', with: milestone1.title)
find('.btn-search').click
diff --git a/spec/features/search/user_searches_for_wiki_pages_spec.rb b/spec/features/search/user_searches_for_wiki_pages_spec.rb
index fc60b6244d9..6bf1407fd4f 100644
--- a/spec/features/search/user_searches_for_wiki_pages_spec.rb
+++ b/spec/features/search/user_searches_for_wiki_pages_spec.rb
@@ -19,10 +19,7 @@ RSpec.describe 'User searches for wiki pages', :js do
shared_examples 'search wiki blobs' do
it 'finds a page' do
find('.js-search-project-dropdown').click
-
- page.within('.project-filter') do
- click_link(project.full_name)
- end
+ find('[data-testid="project-filter"]').click_link(project.full_name)
fill_in('dashboard_search', with: search_term)
find('.btn-search').click
diff --git a/spec/features/search/user_uses_search_filters_spec.rb b/spec/features/search/user_uses_search_filters_spec.rb
index 080cced21c3..a1afba1a371 100644
--- a/spec/features/search/user_uses_search_filters_spec.rb
+++ b/spec/features/search/user_uses_search_filters_spec.rb
@@ -28,7 +28,7 @@ RSpec.describe 'User uses search filters', :js do
expect(find('.js-search-group-dropdown')).to have_content(group.name)
- page.within('.project-filter') do
+ page.within('[data-testid="project-filter"]') do
find('.js-search-project-dropdown').click
wait_for_requests
@@ -57,7 +57,7 @@ RSpec.describe 'User uses search filters', :js do
it 'shows a project' do
visit search_path
- page.within('.project-filter') do
+ page.within('[data-testid="project-filter"]') do
find('.js-search-project-dropdown').click
wait_for_requests
@@ -77,7 +77,7 @@ RSpec.describe 'User uses search filters', :js do
describe 'clear filter button' do
it 'removes Project filters' do
- link = find('.project-filter .js-search-clear')
+ link = find('[data-testid="project-filter"] .js-search-clear')
params = CGI.parse(URI.parse(link[:href]).query)
expect(params).not_to include(:project_id)
diff --git a/spec/frontend/vue_shared/components/members/table/role_dropdown_spec.js b/spec/frontend/vue_shared/components/members/table/role_dropdown_spec.js
index 1e47953a510..f53aec84c06 100644
--- a/spec/frontend/vue_shared/components/members/table/role_dropdown_spec.js
+++ b/spec/frontend/vue_shared/components/members/table/role_dropdown_spec.js
@@ -30,6 +30,7 @@ describe('RoleDropdown', () => {
wrapper = mount(RoleDropdown, {
propsData: {
member,
+ permissions: {},
...propsData,
},
localVue,
diff --git a/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb b/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb
index 9c9ca7411bf..88c889b4055 100644
--- a/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb
+++ b/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Metrics::RequestsRackMiddleware do
+RSpec.describe Gitlab::Metrics::RequestsRackMiddleware, :aggregate_failures do
let(:app) { double('app') }
subject { described_class.new(app) }
@@ -21,20 +21,15 @@ RSpec.describe Gitlab::Metrics::RequestsRackMiddleware do
allow(app).to receive(:call).and_return([200, nil, nil])
end
- it 'increments requests count' do
- expect(described_class).to receive_message_chain(:http_request_total, :increment).with(method: 'get', status: 200, feature_category: 'unknown')
-
- subject.call(env)
- end
-
RSpec::Matchers.define :a_positive_execution_time do
match { |actual| actual > 0 }
end
- it 'measures execution time' do
+ it 'tracks request count and duration' do
+ expect(described_class).to receive_message_chain(:http_requests_total, :increment).with(method: 'get', status: '200', feature_category: 'unknown')
expect(described_class).to receive_message_chain(:http_request_duration_seconds, :observe).with({ method: 'get' }, a_positive_execution_time)
- Timecop.scale(3600) { subject.call(env) }
+ subject.call(env)
end
context 'request is a health check endpoint' do
@@ -44,15 +39,10 @@ RSpec.describe Gitlab::Metrics::RequestsRackMiddleware do
env['PATH_INFO'] = path
end
- it 'increments health endpoint counter rather than overall counter' do
- expect(described_class).to receive_message_chain(:http_health_requests_total, :increment).with(method: 'get', status: 200)
- expect(described_class).not_to receive(:http_request_total)
-
- subject.call(env)
- end
-
- it 'does not record the request duration' do
+ it 'increments health endpoint counter rather than overall counter and does not record duration' do
expect(described_class).not_to receive(:http_request_duration_seconds)
+ expect(described_class).not_to receive(:http_requests_total)
+ expect(described_class).to receive_message_chain(:http_health_requests_total, :increment).with(method: 'get', status: '200')
subject.call(env)
end
@@ -67,14 +57,9 @@ RSpec.describe Gitlab::Metrics::RequestsRackMiddleware do
env['PATH_INFO'] = path
end
- it 'increments overall counter rather than health endpoint counter' do
- expect(described_class).to receive_message_chain(:http_request_total, :increment).with(method: 'get', status: 200, feature_category: 'unknown')
+ it 'increments regular counters and tracks duration' do
+ expect(described_class).to receive_message_chain(:http_requests_total, :increment).with(method: 'get', status: '200', feature_category: 'unknown')
expect(described_class).not_to receive(:http_health_requests_total)
-
- subject.call(env)
- end
-
- it 'records the request duration' do
expect(described_class)
.to receive_message_chain(:http_request_duration_seconds, :observe)
.with({ method: 'get' }, a_positive_execution_time)
@@ -88,26 +73,18 @@ RSpec.describe Gitlab::Metrics::RequestsRackMiddleware do
context '@app.call throws exception' do
let(:http_request_duration_seconds) { double('http_request_duration_seconds') }
+ let(:http_requests_total) { double('http_requests_total') }
before do
allow(app).to receive(:call).and_raise(StandardError)
allow(described_class).to receive(:http_request_duration_seconds).and_return(http_request_duration_seconds)
+ allow(described_class).to receive(:http_requests_total).and_return(http_requests_total)
end
- it 'increments exceptions count' do
+ it 'tracks the correct metrics' do
expect(described_class).to receive_message_chain(:rack_uncaught_errors_count, :increment)
-
- expect { subject.call(env) }.to raise_error(StandardError)
- end
-
- it 'increments requests count' do
- expect(described_class).to receive_message_chain(:http_request_total, :increment).with(method: 'get', status: 'undefined', feature_category: 'unknown')
-
- expect { subject.call(env) }.to raise_error(StandardError)
- end
-
- it "does't measure request execution time" do
- expect(described_class.http_request_duration_seconds).not_to receive(:increment)
+ expect(described_class).to receive_message_chain(:http_requests_total, :increment).with(method: 'get', status: 'undefined', feature_category: 'unknown')
+ expect(described_class.http_request_duration_seconds).not_to receive(:observe)
expect { subject.call(env) }.to raise_error(StandardError)
end
@@ -119,8 +96,9 @@ RSpec.describe Gitlab::Metrics::RequestsRackMiddleware do
allow(app).to receive(:call).and_return([200, { described_class::FEATURE_CATEGORY_HEADER => 'issue_tracking' }, nil])
end
- it 'adds the feature category to the labels for http_request_total' do
- expect(described_class).to receive_message_chain(:http_request_total, :increment).with(method: 'get', status: 200, feature_category: 'issue_tracking')
+ it 'adds the feature category to the labels for http_requests_total' do
+ expect(described_class).to receive_message_chain(:http_requests_total, :increment).with(method: 'get', status: '200', feature_category: 'issue_tracking')
+ expect(described_class).not_to receive(:http_health_requests_total)
subject.call(env)
end
@@ -128,8 +106,8 @@ RSpec.describe Gitlab::Metrics::RequestsRackMiddleware do
it 'does not record a feature category for health check endpoints' do
env['PATH_INFO'] = '/-/liveness'
- expect(described_class).to receive_message_chain(:http_health_requests_total, :increment).with(method: 'get', status: 200)
- expect(described_class).not_to receive(:http_request_total)
+ expect(described_class).to receive_message_chain(:http_health_requests_total, :increment).with(method: 'get', status: '200')
+ expect(described_class).not_to receive(:http_requests_total)
subject.call(env)
end
@@ -141,21 +119,37 @@ RSpec.describe Gitlab::Metrics::RequestsRackMiddleware do
end
it 'sets the feature category to unknown' do
- expect(described_class).to receive_message_chain(:http_request_total, :increment).with(method: 'get', status: 200, feature_category: 'unknown')
+ expect(described_class).to receive_message_chain(:http_requests_total, :increment).with(method: 'get', status: '200', feature_category: 'unknown')
+ expect(described_class).not_to receive(:http_health_requests_total)
subject.call(env)
end
end
end
- describe '.initialize_http_request_duration_seconds' do
- it "sets labels" do
+ describe '.initialize_metrics', :prometheus do
+ it "sets labels for http_requests_total" do
+ feature_categories = YAML.load_file(Rails.root.join('config', 'feature_categories.yml')).map(&:strip) << described_class::FEATURE_CATEGORY_DEFAULT
expected_labels = []
- described_class::HTTP_METHODS.each do |method|
- expected_labels << { method: method }
+
+ described_class::HTTP_METHODS.each do |method, statuses|
+ statuses.each do |status|
+ feature_categories.each do |feature_category|
+ expected_labels << { method: method.to_s, status: status.to_s, feature_category: feature_category.to_s }
+ end
+ end
end
- described_class.initialize_http_request_duration_seconds
+ described_class.initialize_metrics
+
+ expect(described_class.http_requests_total.values.keys).to contain_exactly(*expected_labels)
+ end
+
+ it 'sets labels for http_request_duration_seconds' do
+ expected_labels = described_class::HTTP_METHODS.keys.map { |method| { method: method } }
+
+ described_class.initialize_metrics
+
expect(described_class.http_request_duration_seconds.values.keys).to include(*expected_labels)
end
end