Commit 40464e19 authored by Alper Akgun's avatar Alper Akgun

Merge branch '339447-migrate-usage-activity-by-stage-secure-metrics' into 'master'

Add instrumentation class to usage-activity-by-stage-secure metrics

See merge request gitlab-org/gitlab!76836
parents 48249300 6ee8e88f
......@@ -9,6 +9,9 @@ product_category: dependency_scanning
value_type: number
status: active
time_frame: 28d
instrumentation_class: CountUsersCreatingCiBuildsMetric
options:
secure_type: dependency_scanning
data_source: database
distribution:
- ee
......
......@@ -9,6 +9,9 @@ product_category: license_compliance
value_type: number
status: active
time_frame: 28d
instrumentation_class: CountUsersCreatingCiBuildsMetric
options:
secure_type: license_management
data_source: database
distribution:
- ee
......
......@@ -9,7 +9,7 @@ product_category: container_scanning
value_type: number
status: active
time_frame: 28d
instrumentation_class: CiBuildDistinctCountMetric
instrumentation_class: CountUsersCreatingCiBuildsMetric
options:
secure_type: container_scanning
data_source: database
......
......@@ -9,6 +9,9 @@ product_category: dynamic_application_security_testing
value_type: number
status: active
time_frame: 28d
instrumentation_class: CountUsersCreatingCiBuildsMetric
options:
secure_type: dast
data_source: database
distribution:
- ee
......
......@@ -9,6 +9,9 @@ product_category: fuzz-testing
value_type: number
status: active
time_frame: 28d
instrumentation_class: CountUsersCreatingCiBuildsMetric
options:
secure_type: apifuzzer_fuzz
data_source: database
distribution:
- ee
......
......@@ -9,6 +9,9 @@ product_category: fuzz-testing
value_type: number
status: active
time_frame: 28d
instrumentation_class: CountUsersCreatingCiBuildsMetric
options:
secure_type: apifuzzer_fuzz_dnd
data_source: database
distribution:
- ee
......
......@@ -9,9 +9,11 @@ product_category: static_application_security_testing
value_type: number
status: active
time_frame: 28d
instrumentation_class: CountUsersCreatingCiBuildsMetric
options:
secure_type: sast
data_source: database
distribution:
- ce
- ee
tier:
- free
......
......@@ -9,9 +9,11 @@ product_category: secret_detection
value_type: number
status: active
time_frame: 28d
instrumentation_class: CountUsersCreatingCiBuildsMetric
options:
secure_type: secret_detection
data_source: database
distribution:
- ce
- ee
tier:
- free
......
......@@ -9,6 +9,9 @@ product_category: fuzz-testing
value_type: number
status: active
time_frame: 28d
instrumentation_class: CountUsersCreatingCiBuildsMetric
options:
secure_type: coverage_fuzzing
data_source: database
distribution:
- ee
......
......@@ -9,6 +9,9 @@ product_category: dependency_scanning
value_type: number
status: active
time_frame: all
instrumentation_class: CountCiBuildsMetric
options:
secure_type: dependency_scanning
data_source: database
distribution:
- ee
......
......@@ -9,6 +9,9 @@ product_category: dependency_scanning
value_type: number
status: active
time_frame: all
instrumentation_class: CountUsersCreatingCiBuildsMetric
options:
secure_type: dependency_scanning
data_source: database
distribution:
- ee
......
......@@ -9,6 +9,9 @@ product_category: license_compliance
value_type: number
status: active
time_frame: all
instrumentation_class: CountUsersCreatingCiBuildsMetric
options:
secure_type: license_management
data_source: database
distribution:
- ee
......
......@@ -9,7 +9,7 @@ product_category: container_scanning
value_type: number
status: active
time_frame: all
instrumentation_class: CiBuildDistinctCountMetric
instrumentation_class: CountUsersCreatingCiBuildsMetric
options:
secure_type: container_scanning
data_source: database
......
......@@ -8,6 +8,9 @@ product_category: dynamic_application_security_testing
value_type: number
status: active
time_frame: all
instrumentation_class: CountCiBuildsMetric
options:
secure_type: dast
data_source: database
data_category: operational
distribution:
......
......@@ -8,6 +8,9 @@ product_category: dynamic_application_security_testing
value_type: number
status: active
time_frame: all
instrumentation_class: CountUsersCreatingCiBuildsMetric
options:
secure_type: dast
data_source: database
data_category: operational
distribution:
......
......@@ -9,6 +9,9 @@ product_category: fuzz-testing
value_type: number
status: active
time_frame: all
instrumentation_class: CountCiBuildsMetric
options:
secure_type: apifuzzer_fuzz
data_source: database
distribution:
- ee
......
......@@ -9,6 +9,9 @@ product_category: fuzz-testing
value_type: number
status: active
time_frame: all
instrumentation_class: CountCiBuildsMetric
options:
secure_type: apifuzzer_fuzz_dnd
data_source: database
distribution:
- ee
......
......@@ -9,6 +9,9 @@ product_category: fuzz-testing
value_type: number
status: active
time_frame: all
instrumentation_class: CountUsersCreatingCiBuildsMetric
options:
secure_type: apifuzzer_fuzz
data_source: database
distribution:
- ee
......
......@@ -9,6 +9,9 @@ product_category: fuzz-testing
value_type: number
status: active
time_frame: all
instrumentation_class: CountUsersCreatingCiBuildsMetric
options:
secure_type: apifuzzer_fuzz_dnd
data_source: database
distribution:
- ee
......
......@@ -9,6 +9,9 @@ product_category: static_application_security_testing
value_type: number
status: active
time_frame: all
instrumentation_class: CountCiBuildsMetric
options:
secure_type: sast
data_source: database
distribution:
- ee
......
......@@ -9,6 +9,9 @@ product_category: secret_detection
value_type: number
status: active
time_frame: all
instrumentation_class: CountCiBuildsMetric
options:
secure_type: secret_detection
data_source: database
distribution:
- ee
......
......@@ -9,9 +9,11 @@ product_category: static_application_security_testing
value_type: number
status: active
time_frame: all
instrumentation_class: CountUsersCreatingCiBuildsMetric
options:
secure_type: sast
data_source: database
distribution:
- ce
- ee
tier:
- free
......
......@@ -9,9 +9,11 @@ product_category: secret_detection
value_type: number
status: active
time_frame: all
instrumentation_class: CountUsersCreatingCiBuildsMetric
options:
secure_type: secret_detection
data_source: database
distribution:
- ce
- ee
tier:
- free
......
......@@ -9,6 +9,9 @@ product_category: fuzz-testing
value_type: number
status: active
time_frame: all
instrumentation_class: CountCiBuildsMetric
options:
secure_type: coverage_fuzzing
data_source: database
distribution:
- ee
......
......@@ -9,6 +9,9 @@ product_category: fuzz-testing
value_type: number
status: active
time_frame: all
instrumentation_class: CountUsersCreatingCiBuildsMetric
options:
secure_type: coverage_fuzzing
data_source: database
distribution:
- ee
......
......@@ -19,8 +19,7 @@ module EE
SECURE_PRODUCT_TYPES = {
container_scanning: {
name: :container_scanning_jobs,
instrumentation_class_migrated: true
name: :container_scanning_jobs
},
dast: {
name: :dast_jobs
......@@ -154,7 +153,7 @@ module EE
results = SECURE_PRODUCT_TYPES.each_with_object({}) do |(secure_type, attribs), response|
next if secure_type.in?([:license_management, :license_scanning])
response[attribs[:name]] = count(::Ci::Build.where(name: secure_type)) # rubocop:disable CodeReuse/ActiveRecord
response[attribs[:name]] = add_metric('CountCiBuildsMetric', options: { secure_type: secure_type })
end
results[:license_management_jobs] = add_metric("LicenseManagementJobsMetric")
......@@ -383,15 +382,7 @@ module EE
time_frame = metric_time_period(time_period)
SECURE_PRODUCT_TYPES.each do |secure_type, attribs|
results["#{prefix}#{attribs[:name]}".to_sym] =
if attribs[:instrumentation_class_migrated]
add_metric('CiBuildDistinctCountMetric', time_frame: time_frame, options: { secure_type: secure_type })
else
distinct_count(::Ci::Build.where(name: secure_type).where(time_period),
:user_id,
start: minimum_id(::User),
finish: maximum_id(::User))
end
results["#{prefix}#{attribs[:name]}".to_sym] = add_metric('CountUsersCreatingCiBuildsMetric', time_frame: time_frame, options: { secure_type: secure_type })
end
results.merge!(count_secure_pipelines(time_period))
......
# frozen_string_literal: true
module Gitlab
module Usage
module Metrics
module Instrumentations
class CountCiBuildsMetric < DatabaseMetric
relation { ::Ci::Build }
operation :count
def initialize(time_frame:, options: {})
super
raise ArgumentError, "secure_type options attribute is required" unless secure_type.present?
raise ArgumentError, "Attribute: #{secure_type} it not allowed" unless ::EE::Gitlab::UsageData::SECURE_PRODUCT_TYPES.key?(secure_type.to_sym)
end
private
def relation
super.where(name: secure_type) # rubocop: disable CodeReuse/ActiveRecord
end
def secure_type
options[:secure_type]
end
end
end
end
end
end
......@@ -4,12 +4,12 @@ module Gitlab
module Usage
module Metrics
module Instrumentations
class CiBuildDistinctCountMetric < DatabaseMetric
operation :distinct_count, column: :user_id
cache_start_and_finish_as :ci_build_distinct_count_user
class CountUsersCreatingCiBuildsMetric < DatabaseMetric
relation { ::Ci::Build }
operation :distinct_count, column: :user_id
cache_start_and_finish_as :count_users_creating_ci_builds
start { ::User.minimum(:id) }
finish { ::User.maximum(:id) }
......
......@@ -131,7 +131,7 @@ RSpec.describe Gitlab::UsageData do
expect(count_data[:epic_issues]).to eq(2)
end
it 'gathers security products usage data' do
it 'gathers security products usage data', :aggregate_failures do
expect(count_data[:container_scanning_jobs]).to eq(1)
expect(count_data[:dast_jobs]).to eq(1)
expect(count_data[:dependency_scanning_jobs]).to eq(1)
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CiBuildDistinctCountMetric do
before_all do
user = create(:user)
create(:ci_build, name: 'dast')
create(:ci_build, name: 'container_scanning', user: user)
create(:ci_build, name: 'container_scanning', user: user)
end
it_behaves_like 'a correct instrumented metric value', { time_frame: 'all', data_source: 'database', options: { secure_type: 'container_scanning' } } do
let(:expected_value) { 1 }
end
it 'raises an exception if secure_type option is not present' do
expect { described_class.new }.to raise_error(ArgumentError)
end
it 'raises an exception if secure_type option is invalid' do
expect { described_class.new(option: { secure_type: 'invalid_type' }) }.to raise_error(ArgumentError)
end
context 'with cache_start_and_finish_as called' do
before do
allow_next_instance_of(Gitlab::Database::BatchCounter) do |batch_counter|
allow(batch_counter).to receive(:transaction_open?).and_return(false)
end
end
it 'caches using the key name passed', :request_store, :use_clean_rails_redis_caching do
expect(Gitlab::Cache).to receive(:fetch_once).with('metric_instrumentation/ci_build_distinct_count_user_minimum_id', any_args).and_call_original
expect(Gitlab::Cache).to receive(:fetch_once).with('metric_instrumentation/ci_build_distinct_count_user_maximum_id', any_args).and_call_original
described_class.new(time_frame: 'all', options: { secure_type: 'container_scanning' }).value
expect(Rails.cache.read('metric_instrumentation/ci_build_distinct_count_user_minimum_id')).to eq(::User.minimum(:id))
expect(Rails.cache.read('metric_instrumentation/ci_build_distinct_count_user_maximum_id')).to eq(::User.maximum(:id))
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountCiBuildsMetric do
RSpec.shared_examples 'a correct secure type instrumented metric value' do |params|
let(:expected_value) { params[:expected_value] }
before_all do
user = create(:user)
user2 = create(:user)
secure_types = %w[
container_scanning
dast
dependency_scanning
license_management
license_scanning
sast
secret_detection
coverage_fuzzing
apifuzzer_fuzz
apifuzzer_fuzz_dnd
].freeze
secure_types.each do |secure_type|
create(:ci_build, name: secure_type, user: user, created_at: 3.days.ago)
create(:ci_build, name: secure_type, user: user)
create(:ci_build, name: secure_type, user: user2, created_at: 30.days.ago)
end
end
context 'with secure_type container_scanning' do
let(:secure_type) { 'container_scanning' }
it_behaves_like 'a correct instrumented metric value and query', { time_frame: params[:time_frame], data_source: 'database', options: { secure_type: 'container_scanning' } }
end
context 'with secure_type dast' do
let(:secure_type) { 'dast' }
it_behaves_like 'a correct instrumented metric value and query', { time_frame: params[:time_frame], data_source: 'database', options: { secure_type: 'dast' } }
end
context 'with secure_type dependency_scanning' do
let(:secure_type) { 'dependency_scanning' }
it_behaves_like 'a correct instrumented metric value and query', { time_frame: params[:time_frame], data_source: 'database', options: { secure_type: 'dependency_scanning' } }
end
context 'with secure_type license_management' do
let(:secure_type) { 'license_management' }
it_behaves_like 'a correct instrumented metric value and query', { time_frame: params[:time_frame], data_source: 'database', options: { secure_type: 'license_management' } }
end
context 'with secure_type license_scanning' do
let(:secure_type) { 'license_scanning' }
it_behaves_like 'a correct instrumented metric value and query', { time_frame: params[:time_frame], data_source: 'database', options: { secure_type: 'license_scanning' } }
end
context 'with secure_type sast' do
let(:secure_type) { 'sast' }
it_behaves_like 'a correct instrumented metric value and query', { time_frame: params[:time_frame], data_source: 'database', options: { secure_type: 'sast' } }
end
context 'with secure_type secret_detection' do
let(:secure_type) { 'secret_detection' }
it_behaves_like 'a correct instrumented metric value and query', { time_frame: params[:time_frame], data_source: 'database', options: { secure_type: 'secret_detection' } }
end
context 'with secure_type coverage_fuzzing' do
let(:secure_type) { 'coverage_fuzzing' }
it_behaves_like 'a correct instrumented metric value and query', { time_frame: params[:time_frame], data_source: 'database', options: { secure_type: 'coverage_fuzzing' } }
end
context 'with secure_type apifuzzer_fuzz' do
let(:secure_type) { 'apifuzzer_fuzz' }
it_behaves_like 'a correct instrumented metric value and query', { time_frame: params[:time_frame], data_source: 'database', options: { secure_type: 'apifuzzer_fuzz' } }
end
context 'with secure_type apifuzzer_fuzz_dnd' do
let(:secure_type) { 'apifuzzer_fuzz_dnd' }
it_behaves_like 'a correct instrumented metric value and query', { time_frame: params[:time_frame], data_source: 'database', options: { secure_type: 'apifuzzer_fuzz_dnd' } }
end
end
context 'with time_frame all' do
let(:expected_query) { "SELECT COUNT(\"ci_builds\".\"id\") FROM \"ci_builds\" WHERE \"ci_builds\".\"type\" = 'Ci::Build' AND \"ci_builds\".\"name\" = '#{secure_type}'" }
it_behaves_like 'a correct secure type instrumented metric value', { time_frame: 'all', expected_value: 3 }
end
context 'with time_frame 28d' do
let(:start) { 30.days.ago.to_s(:db) }
let(:finish) { 2.days.ago.to_s(:db) }
let(:expected_query) { "SELECT COUNT(\"ci_builds\".\"id\") FROM \"ci_builds\" WHERE \"ci_builds\".\"type\" = 'Ci::Build' AND \"ci_builds\".\"created_at\" BETWEEN '#{start}' AND '#{finish}' AND \"ci_builds\".\"name\" = '#{secure_type}'" }
it_behaves_like 'a correct secure type instrumented metric value', { time_frame: '28d', expected_value: 1 }
end
it 'raises an exception if secure_type option is not present' do
expect { described_class.new }.to raise_error(ArgumentError)
end
it 'raises an exception if secure_type option is invalid' do
expect { described_class.new(option: { secure_type: 'invalid_type' }) }.to raise_error(ArgumentError)
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountUsersCreatingCiBuildsMetric do
RSpec.shared_examples 'a correct secure type instrumented metric value' do |params|
let(:expected_value) { params[:expected_value] }
before_all do
user = create(:user)
user2 = create(:user)
secure_types = %w[
container_scanning
dast
dependency_scanning
license_management
license_scanning
sast
secret_detection
coverage_fuzzing
apifuzzer_fuzz
apifuzzer_fuzz_dnd
].freeze
secure_types.each do |secure_type|
create(:ci_build, name: secure_type, user: user, created_at: 3.days.ago)
create(:ci_build, name: secure_type, user: user)
create(:ci_build, name: secure_type, user: user2, created_at: 30.days.ago)
end
end
context 'with secure_type container_scanning' do
let(:secure_type) { 'container_scanning' }
it_behaves_like 'a correct instrumented metric value and query', { time_frame: params[:time_frame], data_source: 'database', options: { secure_type: 'container_scanning' } }
end
context 'with secure_type dast' do
let(:secure_type) { 'dast' }
it_behaves_like 'a correct instrumented metric value and query', { time_frame: params[:time_frame], data_source: 'database', options: { secure_type: 'dast' } }
end
context 'with secure_type dependency_scanning' do
let(:secure_type) { 'dependency_scanning' }
it_behaves_like 'a correct instrumented metric value and query', { time_frame: params[:time_frame], data_source: 'database', options: { secure_type: 'dependency_scanning' } }
end
context 'with secure_type license_management' do
let(:secure_type) { 'license_management' }
it_behaves_like 'a correct instrumented metric value and query', { time_frame: params[:time_frame], data_source: 'database', options: { secure_type: 'license_management' } }
end
context 'with secure_type license_scanning' do
let(:secure_type) { 'license_scanning' }
it_behaves_like 'a correct instrumented metric value and query', { time_frame: params[:time_frame], data_source: 'database', options: { secure_type: 'license_scanning' } }
end
context 'with secure_type sast' do
let(:secure_type) { 'sast' }
it_behaves_like 'a correct instrumented metric value and query', { time_frame: params[:time_frame], data_source: 'database', options: { secure_type: 'sast' } }
end
context 'with secure_type secret_detection' do
let(:secure_type) { 'secret_detection' }
it_behaves_like 'a correct instrumented metric value and query', { time_frame: params[:time_frame], data_source: 'database', options: { secure_type: 'secret_detection' } }
end
context 'with secure_type coverage_fuzzing' do
let(:secure_type) { 'coverage_fuzzing' }
it_behaves_like 'a correct instrumented metric value and query', { time_frame: params[:time_frame], data_source: 'database', options: { secure_type: 'coverage_fuzzing' } }
end
context 'with secure_type apifuzzer_fuzz' do
let(:secure_type) { 'apifuzzer_fuzz' }
it_behaves_like 'a correct instrumented metric value and query', { time_frame: params[:time_frame], data_source: 'database', options: { secure_type: 'apifuzzer_fuzz' } }
end
context 'with secure_type apifuzzer_fuzz_dnd' do
let(:secure_type) { 'apifuzzer_fuzz_dnd' }
it_behaves_like 'a correct instrumented metric value and query', { time_frame: params[:time_frame], data_source: 'database', options: { secure_type: 'apifuzzer_fuzz_dnd' } }
end
end
context 'with time_frame all' do
let(:expected_query) { "SELECT COUNT(DISTINCT \"ci_builds\".\"user_id\") FROM \"ci_builds\" WHERE \"ci_builds\".\"type\" = 'Ci::Build' AND \"ci_builds\".\"name\" = '#{secure_type}'" }
it_behaves_like 'a correct secure type instrumented metric value', { time_frame: 'all', expected_value: 2 }
end
context 'with time_frame 28d' do
let(:start) { 30.days.ago.to_s(:db) }
let(:finish) { 2.days.ago.to_s(:db) }
let(:expected_query) { "SELECT COUNT(DISTINCT \"ci_builds\".\"user_id\") FROM \"ci_builds\" WHERE \"ci_builds\".\"type\" = 'Ci::Build' AND \"ci_builds\".\"created_at\" BETWEEN '#{start}' AND '#{finish}' AND \"ci_builds\".\"name\" = '#{secure_type}'" }
it_behaves_like 'a correct secure type instrumented metric value', { time_frame: '28d', expected_value: 1 }
end
it 'raises an exception if secure_type option is not present' do
expect { described_class.new }.to raise_error(ArgumentError)
end
it 'raises an exception if secure_type option is invalid' do
expect { described_class.new(option: { secure_type: 'invalid_type' }) }.to raise_error(ArgumentError)
end
context 'with cache_start_and_finish_as called' do
before do
allow_next_instance_of(Gitlab::Database::BatchCounter) do |batch_counter|
allow(batch_counter).to receive(:transaction_open?).and_return(false)
end
end
it 'caches using the key name passed', :request_store, :use_clean_rails_redis_caching do
expect(Gitlab::Cache).to receive(:fetch_once).with('metric_instrumentation/count_users_creating_ci_builds_minimum_id', any_args).and_call_original
expect(Gitlab::Cache).to receive(:fetch_once).with('metric_instrumentation/count_users_creating_ci_builds_maximum_id', any_args).and_call_original
described_class.new(time_frame: 'all', options: { secure_type: 'container_scanning' }).value
expect(Rails.cache.read('metric_instrumentation/count_users_creating_ci_builds_minimum_id')).to eq(::User.minimum(:id))
expect(Rails.cache.read('metric_instrumentation/count_users_creating_ci_builds_maximum_id')).to eq(::User.maximum(:id))
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