Commit 3ac320ce authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents eea422b0 f5a67298
......@@ -64,7 +64,7 @@ module NavHelper
end
def admin_analytics_nav_links
%w(dev_ops_report)
%w(dev_ops_report usage_trends)
end
def group_issues_sub_menu_items
......
# frozen_string_literal: true
class PlanLimits < ApplicationRecord
include IgnorableColumns
ignore_column :ci_max_artifact_size_running_container_scanning, remove_with: '14.3', remove_after: '2021-08-22'
LimitUndefinedError = Class.new(StandardError)
belongs_to :plan
......
......@@ -37,7 +37,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
:idempotent: true
:idempotent:
:tags: []
- :name: authorized_project_update:authorized_project_update_user_refresh_over_user_range
:worker_name: AuthorizedProjectUpdate::UserRefreshOverUserRangeWorker
......
# frozen_string_literal: true
module AuthorizedProjectUpdate
class UserRefreshFromReplicaWorker < ::AuthorizedProjectsWorker
class UserRefreshFromReplicaWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
sidekiq_options retry: 3
feature_category :authentication_and_authorization
urgency :low
queue_namespace :authorized_project_update
# This job will not be deduplicated since it is marked with
# `data_consistency :delayed` and not `idempotent!`
# See https://gitlab.com/gitlab-org/gitlab/-/issues/325291
deduplicate :until_executing, including_scheduled: true
idempotent!
data_consistency :delayed
def perform(user_id)
user = User.find_by_id(user_id)
return unless user
if Feature.enabled?(:user_refresh_from_replica_worker_uses_replica_db)
enqueue_project_authorizations_refresh(user) if project_authorizations_needs_refresh?(user)
else
use_primary_database
user.refresh_authorized_projects(source: self.class.name)
end
end
private
def use_primary_database
if ::Gitlab::Database::LoadBalancing.enable?
::Gitlab::Database::LoadBalancing::Session.current.use_primary!
end
end
def project_authorizations_needs_refresh?(user)
AuthorizedProjectUpdate::FindRecordsDueForRefreshService.new(user).needs_refresh?
end
def enqueue_project_authorizations_refresh(user)
with_context(user: user, related_class: current_caller_id) do
AuthorizedProjectUpdate::UserRefreshWithLowUrgencyWorker.perform_async(user.id)
end
end
# This worker will start reading data from the replica database soon
# Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/333219
# We use this so that we can obtain the details of the original caller
# in the enqueued `AuthorizedProjectUpdate::UserRefreshWithLowUrgencyWorker` job.
def current_caller_id
Gitlab::ApplicationContext.current_context_attribute('meta.caller_id').presence
end
end
end
---
name: user_refresh_from_replica_worker_uses_replica_db
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64276
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/334766
milestone: '14.1'
type: development
group: group::access
default_enabled: false
# frozen_string_literal: true
class AddPlanLimitsMaxSizeClusterImageScanningColumn < ActiveRecord::Migration[6.0]
def change
add_column :plan_limits, :ci_max_artifact_size_cluster_image_scanning, :integer, null: false, default: 0
end
end
b37bf7db9c00c8f54c0ccca2d418f1279e12ff7e5b71347966494dc5645eb648
\ No newline at end of file
......@@ -16352,7 +16352,8 @@ CREATE TABLE plan_limits (
ci_registered_project_runners integer DEFAULT 1000 NOT NULL,
web_hook_calls integer DEFAULT 0 NOT NULL,
ci_daily_pipeline_schedule_triggers integer DEFAULT 0 NOT NULL,
ci_max_artifact_size_running_container_scanning integer DEFAULT 0 NOT NULL
ci_max_artifact_size_running_container_scanning integer DEFAULT 0 NOT NULL,
ci_max_artifact_size_cluster_image_scanning integer DEFAULT 0 NOT NULL
);
CREATE SEQUENCE plan_limits_id_seq
......@@ -426,6 +426,7 @@ setting is used:
| `ci_max_artifact_size_archive` | 0 |
| `ci_max_artifact_size_browser_performance` | 0 |
| `ci_max_artifact_size_cluster_applications` | 0 |
| `ci_max_artifact_size_cluster_image_scanning` | 0 |
| `ci_max_artifact_size_cobertura` | 0 |
| `ci_max_artifact_size_codequality` | 0 |
| `ci_max_artifact_size_container_scanning` | 0 |
......@@ -444,7 +445,6 @@ setting is used:
| `ci_max_artifact_size_network_referee` | 0 |
| `ci_max_artifact_size_performance` | 0 |
| `ci_max_artifact_size_requirements` | 0 |
| `ci_max_artifact_size_running_container_scanning` | 0 |
| `ci_max_artifact_size_sast` | 0 |
| `ci_max_artifact_size_secret_detection` | 0 |
| `ci_max_artifact_size_terraform` | 5 MB ([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37018) in GitLab 13.3) |
......
......@@ -12652,11 +12652,11 @@ Represents summary of a security report.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="securityreportsummaryapifuzzing"></a>`apiFuzzing` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `api_fuzzing` scan. |
| <a id="securityreportsummaryclusterimagescanning"></a>`clusterImageScanning` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `cluster_image_scanning` scan. |
| <a id="securityreportsummarycontainerscanning"></a>`containerScanning` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `container_scanning` scan. |
| <a id="securityreportsummarycoveragefuzzing"></a>`coverageFuzzing` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `coverage_fuzzing` scan. |
| <a id="securityreportsummarydast"></a>`dast` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `dast` scan. |
| <a id="securityreportsummarydependencyscanning"></a>`dependencyScanning` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `dependency_scanning` scan. |
| <a id="securityreportsummaryrunningcontainerscanning"></a>`runningContainerScanning` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `running_container_scanning` scan. |
| <a id="securityreportsummarysast"></a>`sast` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `sast` scan. |
| <a id="securityreportsummarysecretdetection"></a>`secretDetection` | [`SecurityReportSummarySection`](#securityreportsummarysection) | Aggregated counts for the `secret_detection` scan. |
......@@ -13511,7 +13511,7 @@ Represents a vulnerability.
| <a id="vulnerabilitynotes"></a>`notes` | [`NoteConnection!`](#noteconnection) | All notes on this noteable. (see [Connections](#connections)) |
| <a id="vulnerabilityprimaryidentifier"></a>`primaryIdentifier` | [`VulnerabilityIdentifier`](#vulnerabilityidentifier) | Primary identifier of the vulnerability. |
| <a id="vulnerabilityproject"></a>`project` | [`Project`](#project) | The project on which the vulnerability was found. |
| <a id="vulnerabilityreporttype"></a>`reportType` | [`VulnerabilityReportType`](#vulnerabilityreporttype) | Type of the security report that found the vulnerability (SAST, DEPENDENCY_SCANNING, CONTAINER_SCANNING, DAST, SECRET_DETECTION, COVERAGE_FUZZING, API_FUZZING, RUNNING_CONTAINER_SCANNING). `Scan Type` in the UI. |
| <a id="vulnerabilityreporttype"></a>`reportType` | [`VulnerabilityReportType`](#vulnerabilityreporttype) | Type of the security report that found the vulnerability (SAST, DEPENDENCY_SCANNING, CONTAINER_SCANNING, DAST, SECRET_DETECTION, COVERAGE_FUZZING, API_FUZZING, CLUSTER_IMAGE_SCANNING). `Scan Type` in the UI. |
| <a id="vulnerabilityresolvedat"></a>`resolvedAt` | [`Time`](#time) | Timestamp of when the vulnerability state was changed to resolved. |
| <a id="vulnerabilityresolvedby"></a>`resolvedBy` | [`UserCore`](#usercore) | The user that resolved the vulnerability. |
| <a id="vulnerabilityresolvedondefaultbranch"></a>`resolvedOnDefaultBranch` | [`Boolean!`](#boolean) | Indicates whether the vulnerability is fixed on the default branch or not. |
......@@ -15187,11 +15187,11 @@ The type of the security scan that found the vulnerability.
| Value | Description |
| ----- | ----------- |
| <a id="vulnerabilityreporttypeapi_fuzzing"></a>`API_FUZZING` | |
| <a id="vulnerabilityreporttypecluster_image_scanning"></a>`CLUSTER_IMAGE_SCANNING` | |
| <a id="vulnerabilityreporttypecontainer_scanning"></a>`CONTAINER_SCANNING` | |
| <a id="vulnerabilityreporttypecoverage_fuzzing"></a>`COVERAGE_FUZZING` | |
| <a id="vulnerabilityreporttypedast"></a>`DAST` | |
| <a id="vulnerabilityreporttypedependency_scanning"></a>`DEPENDENCY_SCANNING` | |
| <a id="vulnerabilityreporttyperunning_container_scanning"></a>`RUNNING_CONTAINER_SCANNING` | |
| <a id="vulnerabilityreporttypesast"></a>`SAST` | |
| <a id="vulnerabilityreporttypesecret_detection"></a>`SECRET_DETECTION` | |
......
......@@ -17318,6 +17318,18 @@ Status: `data_available`
Tiers:
### `usage_activity_by_stage.secure.cluster_image_scanning_scans`
Counts cluster image scanning jobs
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_all/20210618124854_cluster_image_scanning_scans.yml)
Group: `group::container security`
Status: `implemented`
Tiers: `ultimate`
### `usage_activity_by_stage.secure.container_scanning_scans`
Counts container scanning jobs
......@@ -17366,18 +17378,6 @@ Status: `data_available`
Tiers: `ultimate`
### `usage_activity_by_stage.secure.running_container_scanning_scans`
Counts running container scanning jobs
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_all/20210618124854_running_container_scanning_scans.yml)
Group: `group::container security`
Status: `data_available`
Tiers: `ultimate`
### `usage_activity_by_stage.secure.sast_scans`
Counts sast jobs
......@@ -19394,6 +19394,30 @@ Status: `data_available`
Tiers: `free`
### `usage_activity_by_stage_monthly.secure.cluster_image_scanning_pipeline`
Pipelines containing a Cluster Image Scanning job
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210618125224_cluster_image_scanning_pipeline.yml)
Group: `group::container security`
Status: `implemented`
Tiers: `ultimate`
### `usage_activity_by_stage_monthly.secure.cluster_image_scanning_scans`
Counts cluster image scanning jobs
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210618101233_cluster_image_scanning_scans.yml)
Group: `group::container security`
Status: `implemented`
Tiers: `ultimate`
### `usage_activity_by_stage_monthly.secure.container_scanning_pipeline`
Pipelines containing a Container Scanning job
......@@ -19490,30 +19514,6 @@ Status: `data_available`
Tiers: `ultimate`
### `usage_activity_by_stage_monthly.secure.running_container_scanning_pipeline`
Pipelines containing a Running Container Scanning job
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210618125224_running_container_scanning_pipeline.yml)
Group: `group::container security`
Status: `data_available`
Tiers: `ultimate`
### `usage_activity_by_stage_monthly.secure.running_container_scanning_scans`
Counts running container scanning jobs
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210618101233_running_container_scanning_scans.yml)
Group: `group::container security`
Status: `data_available`
Tiers: `ultimate`
### `usage_activity_by_stage_monthly.secure.sast_pipeline`
Counts of Pipelines that have at least 1 SAST job
......
......@@ -11,7 +11,7 @@ module EE
dast: 3,
coverage_fuzzing: 5,
api_fuzzing: 6,
running_container_scanning: 7
cluster_image_scanning: 7
}.freeze
class_methods do
......
......@@ -28,6 +28,7 @@ module IncidentManagement
validates :rule_id, presence: true, uniqueness: { scope: [:alert_id] }
delegate :project, to: :alert
delegate :policy, to: :rule, allow_nil: true
end
end
end
......@@ -24,7 +24,7 @@ module Security
secret_detection: 5,
coverage_fuzzing: 6,
api_fuzzing: 7,
running_container_scanning: 8
cluster_image_scanning: 8
}
scope :by_scan_types, -> (scan_types) { where(scan_type: scan_types) }
......
......@@ -112,6 +112,10 @@ module EE
issuables_service(noteable, project, author).publish_issue_to_status_page
end
def notify_via_escalation(noteable, project, recipients, escalation_policy, oncall_schedule)
escalations_service(noteable, project).notify_via_escalation(recipients, escalation_policy: escalation_policy, oncall_schedule: oncall_schedule)
end
private
def issuables_service(noteable, project, author)
......@@ -129,5 +133,9 @@ module EE
def vulnerabilities_service(noteable, project, author)
::SystemNotes::VulnerabilitiesService.new(noteable: noteable, project: project, author: author)
end
def escalations_service(noteable, project)
::SystemNotes::EscalationsService.new(noteable: noteable, project: project)
end
end
end
......@@ -3,6 +3,8 @@
module IncidentManagement
module PendingEscalations
class ProcessService < BaseService
include Gitlab::Utils::StrongMemoize
def initialize(escalation)
@escalation = escalation
@project = escalation.project
......@@ -17,6 +19,7 @@ module IncidentManagement
return if target_status_exceeded_rule?
notify_recipients
create_system_notes
destroy_escalation!
end
......@@ -42,11 +45,17 @@ module IncidentManagement
NotificationService
.new
.async
.notify_oncall_users_of_alert(oncall_notification_recipients.to_a, target)
.notify_oncall_users_of_alert(oncall_notification_recipients, target)
end
def create_system_notes
SystemNoteService.notify_via_escalation(target, project, oncall_notification_recipients, escalation.policy, oncall_schedule)
end
def oncall_notification_recipients
::IncidentManagement::OncallUsersFinder.new(project, schedule: oncall_schedule).execute
strong_memoize(:oncall_notification_recipients) do
::IncidentManagement::OncallUsersFinder.new(project, schedule: oncall_schedule).execute.to_a
end
end
def destroy_escalation!
......
# frozen_string_literal: true
module SystemNotes
class EscalationsService < ::SystemNotes::BaseService
def initialize(noteable: nil, project: nil)
@noteable = noteable
@project = project
@author = User.alert_bot
end
def notify_via_escalation(recipients, escalation_policy: nil, oncall_schedule: nil)
body = if escalation_policy
"notified #{recipients.map(&:to_reference).to_sentence} of this alert via escalation policy **#{escalation_policy.name}**"
else
"notified #{recipients.map(&:to_reference).to_sentence} of this alert via schedule **#{oncall_schedule.name}**, per an escalation rule which no longer exists"
end
create_note(NoteSummary.new(noteable, project, author, body, action: 'new_alert_added'))
end
end
end
......@@ -424,7 +424,7 @@
:tags: []
- :name: cronjob:update_max_seats_used_for_gitlab_com_subscriptions
:worker_name: UpdateMaxSeatsUsedForGitlabComSubscriptionsWorker
:feature_category: :license
:feature_category: :utilization
:has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
......
......@@ -6,7 +6,7 @@ class UpdateMaxSeatsUsedForGitlabComSubscriptionsWorker # rubocop:disable Scalab
sidekiq_options retry: 3
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext
feature_category :license
feature_category :utilization
worker_resource_boundary :cpu
# rubocop: disable CodeReuse/ActiveRecord
......
---
key_path: usage_activity_by_stage.secure.running_container_scanning_scans
description: 'Counts running container scanning jobs'
key_path: usage_activity_by_stage_monthly.secure.cluster_image_scanning_scans
description: 'Counts cluster image scanning jobs'
product_section: sec
product_stage: protect
product_group: group::container security
product_category: container_scanning
value_type: number
status: data_available
status: implemented
time_frame: all
data_source: database
data_category: Optional
......
---
key_path: usage_activity_by_stage_monthly.secure.running_container_scanning_pipeline
description: Pipelines containing a Running Container Scanning job
key_path: usage_activity_by_stage_monthly.secure.cluster_image_scanning_pipeline
description: Pipelines containing a Cluster Image Scanning job
product_section: sec
product_stage: protect
product_group: group::container security
product_category: container_scanning
value_type: number
status: data_available
status: implemented
time_frame: 28d
data_source: database
data_category: Optional
......
---
key_path: usage_activity_by_stage_monthly.secure.running_container_scanning_scans
description: 'Counts running container scanning jobs'
key_path: usage_activity_by_stage.secure.cluster_image_scanning_scans
description: 'Counts cluster image scanning jobs'
product_section: sec
product_stage: protect
product_group: group::container security
product_category: container_scanning
value_type: number
status: data_available
status: implemented
time_frame: all
data_source: database
data_category: Optional
......
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Report format for GitLab Running Container Scanning",
"description": "This schema provides the the report format for Running Container Scanning (https://docs.gitlab.com/ee/user/application_security/running_container_scanning).",
"title": "Report format for GitLab Cluster Image Scanning",
"description": "This schema provides the the report format for Cluster Image Scanning.",
"definitions": {
"detail_type": {
"oneOf": [
......
......@@ -18,7 +18,7 @@ RSpec.describe Resolvers::SecurityReportSummaryResolver do
dast: [:scanned_resources_count, :vulnerabilities_count, :scans],
sast: [:scanned_resources_count, :vulnerabilities_count],
container_scanning: [:scanned_resources_count, :vulnerabilities_count],
running_container_scanning: [:scanned_resources_count, :vulnerabilities_count],
cluster_image_scanning: [:scanned_resources_count, :vulnerabilities_count],
dependency_scanning: [:scanned_resources_count, :vulnerabilities_count],
coverage_fuzzing: [:scanned_resources_count, :vulnerabilities_count]
}
......
......@@ -6,7 +6,7 @@ RSpec.describe GitlabSchema.types['SecurityReportSummary'] do
specify { expect(described_class.graphql_name).to eq('SecurityReportSummary') }
it 'has specific fields' do
expected_fields = %w[dast sast containerScanning dependencyScanning runningContainerScanning]
expected_fields = %w[dast sast containerScanning dependencyScanning clusterImageScanning]
expect(described_class).to include_graphql_fields(*expected_fields)
end
......
......@@ -4,6 +4,6 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['VulnerabilityReportType'] do
it 'exposes all vulnerability report types' do
expect(described_class.values.keys).to match_array(%w[SAST SECRET_DETECTION DAST RUNNING_CONTAINER_SCANNING CONTAINER_SCANNING DEPENDENCY_SCANNING COVERAGE_FUZZING API_FUZZING])
expect(described_class.values.keys).to match_array(%w[SAST SECRET_DETECTION DAST CLUSTER_IMAGE_SCANNING CONTAINER_SCANNING DEPENDENCY_SCANNING COVERAGE_FUZZING API_FUZZING])
end
end
......@@ -6,7 +6,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Validators::SchemaValidator do
using RSpec::Parameterized::TableSyntax
where(:report_type, :expected_errors, :valid_data) do
:running_container_scanning | ['root is missing required keys: vulnerabilities'] | { 'version' => '10.0.0', 'vulnerabilities' => [] }
:cluster_image_scanning | ['root is missing required keys: vulnerabilities'] | { 'version' => '10.0.0', 'vulnerabilities' => [] }
:container_scanning | ['root is missing required keys: vulnerabilities'] | { 'version' => '10.0.0', 'vulnerabilities' => [] }
:coverage_fuzzing | ['root is missing required keys: vulnerabilities'] | { 'version' => '10.0.0', 'vulnerabilities' => [] }
:dast | ['root is missing required keys: vulnerabilities'] | { 'version' => '10.0.0', 'vulnerabilities' => [] }
......
......@@ -18,7 +18,7 @@ RSpec.describe Vulnerability do
secret_detection: 4,
coverage_fuzzing: 5,
api_fuzzing: 6,
running_container_scanning: 7 }
cluster_image_scanning: 7 }
end
let_it_be(:project) { create(:project) }
......
......@@ -11,6 +11,7 @@ RSpec.describe IncidentManagement::PendingEscalations::Alert do
it { is_expected.to validate_presence_of(:process_at) }
it { is_expected.to validate_presence_of(:status) }
it { is_expected.to delegate_method(:project).to(:alert) }
it { is_expected.to delegate_method(:policy).to(:rule).allow_nil }
it { is_expected.to validate_uniqueness_of(:rule_id).scoped_to([:alert_id]) }
end
......
......@@ -49,6 +49,14 @@ RSpec.describe IncidentManagement::PendingEscalations::ProcessService do
it_behaves_like 'sends on-call notification'
it_behaves_like 'deletes the escalation'
it 'creates a system note' do
expect(SystemNoteService)
.to receive(:notify_via_escalation).with(alert, project, [a_kind_of(User)], escalation_policy, schedule_1)
.and_call_original
expect { execute }.to change(Note, :count).by(1)
end
context 'feature flag is off' do
before do
stub_feature_flags(escalation_policies_mvc: false)
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe SystemNotes::EscalationsService do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:user_2) { create(:user) }
let_it_be(:author) { User.alert_bot }
describe '#notify_via_escalation' do
subject { described_class.new(noteable: noteable, project: project).notify_via_escalation([user, user_2], escalation_policy: escalation_policy, oncall_schedule: oncall_schedule) }
let_it_be(:escalation_policy) { create(:incident_management_escalation_policy, project: project) }
let_it_be(:oncall_schedule) { create(:incident_management_oncall_schedule, project: project) }
let_it_be(:noteable) { create(:alert_management_alert, project: project) }
it_behaves_like 'a system note' do
let(:action) { 'new_alert_added' }
end
it 'posts the correct text to the system note' do
expect(subject.note).to match("notified #{user.to_reference} and #{user_2.to_reference} of this alert via escalation policy **#{escalation_policy.name}**")
end
context 'when policy is missing' do
let_it_be(:escalation_policy) { nil }
it 'posts the correct text to the system note' do
expect(subject.note).to match("notified #{user.to_reference} and #{user_2.to_reference} of this alert via schedule **#{oncall_schedule.name}**, per an escalation rule which no longer exists")
end
end
end
end
......@@ -185,7 +185,7 @@ RSpec.describe PlanLimits do
ci_max_artifact_size_junit
ci_max_artifact_size_sast
ci_max_artifact_size_dast
ci_max_artifact_size_running_container_scanning
ci_max_artifact_size_cluster_image_scanning
ci_max_artifact_size_codequality
ci_max_artifact_size_license_management
ci_max_artifact_size_performance
......
......@@ -3,9 +3,97 @@
require 'spec_helper'
RSpec.describe AuthorizedProjectUpdate::UserRefreshFromReplicaWorker do
let_it_be(:project) { create(:project) }
let_it_be(:user) { project.namespace.owner }
let(:execute_worker) { subject.perform(user.id) }
it 'is labeled as low urgency' do
expect(described_class.get_urgency).to eq(:low)
end
it_behaves_like "refreshes user's project authorizations"
it_behaves_like 'worker with data consistency',
described_class,
data_consistency: :delayed
describe '#perform' do
it 'checks if a project_authorization refresh is needed for the user' do
expect(AuthorizedProjectUpdate::FindRecordsDueForRefreshService).to(
receive(:new).with(user).and_call_original)
execute_worker
end
context 'when there are project authorization records due for either removal or addition for a specific user' do
before do
user.project_authorizations.delete_all
end
it 'enqueues a new project authorization update job for the user' do
expect(AuthorizedProjectUpdate::UserRefreshWithLowUrgencyWorker).to receive(:perform_async).with(user.id)
execute_worker
end
context 'setting `meta.caller_id` as `meta.related_class` in the context of the newly enqueued `UserRefreshWithLowUrgencyWorker` job' do
context 'when the `UserRefreshFromReplicaWorker` job has a `caller_id` set' do
it 'sets the same `caller_id` as `related_class`' do
expect(AuthorizedProjectUpdate::UserRefreshWithLowUrgencyWorker).to receive(:perform_async).with(user.id) do
expect(Gitlab::ApplicationContext.current).to include('meta.related_class' => 'Foo')
end
Gitlab::ApplicationContext.with_context(caller_id: 'Foo') do
execute_worker
end
end
end
context 'when the `UserRefreshFromReplicaWorker` job does not have a `caller_id` set' do
it 'does not set the value of `related_class`' do
expect(AuthorizedProjectUpdate::UserRefreshWithLowUrgencyWorker).to receive(:perform_async).with(user.id) do
expect(Gitlab::ApplicationContext.current).not_to include('meta.related_class')
end
execute_worker
end
end
end
end
context 'when there are no additions or removals to be made to project authorizations for a specific user' do
it 'does not enqueue a new project authorization update job for the user' do
expect(AuthorizedProjectUpdate::UserRefreshWithLowUrgencyWorker).not_to receive(:perform_async)
execute_worker
end
end
context 'when the feature flag `user_refresh_from_replica_worker_uses_replica_db` is disabled' do
before do
stub_feature_flags(user_refresh_from_replica_worker_uses_replica_db: false)
end
context 'when load balancing is enabled' do
before do
allow(Gitlab::Database::LoadBalancing).to receive(:enable?).and_return(true)
end
it 'reads from the primary database' do
expect(Gitlab::Database::LoadBalancing::Session.current)
.to receive(:use_primary!)
execute_worker
end
end
it 'calls Users::RefreshAuthorizedProjectsService' do
source = 'AuthorizedProjectUpdate::UserRefreshFromReplicaWorker'
expect_next_instance_of(Users::RefreshAuthorizedProjectsService, user, { source: source }) do |service|
expect(service).to receive(:execute)
end
execute_worker
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment