diff options
Diffstat (limited to 'spec/lib/gitlab/usage')
9 files changed, 226 insertions, 8 deletions
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_metric_spec.rb index 4c86410d609..b7da9b27e19 100644 --- a/spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_metric_spec.rb +++ b/spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_metric_spec.rb @@ -4,15 +4,30 @@ require 'spec_helper' RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountImportedProjectsMetric do let_it_be(:user) { create(:user) } - let_it_be(:gitea_imports) do - create_list(:project, 3, import_type: 'gitea', creator_id: user.id, created_at: 3.weeks.ago) + + # Project records have to be created chronologically, because of + # metric SQL query optimizations that rely on the fact that `id`s + # increment monotonically over time. + # + # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/89701 + let_it_be(:old_import) { create(:project, import_type: 'gitea', creator_id: user.id, created_at: 2.months.ago) } + let_it_be(:gitea_import_1) { create(:project, import_type: 'gitea', creator_id: user.id, created_at: 21.days.ago) } + + let_it_be(:gitea_import_2) do + create(:project, import_type: 'gitea', creator_id: user.id, created_at: 20.days.ago) end - let_it_be(:bitbucket_imports) do - create_list(:project, 2, import_type: 'bitbucket', creator_id: user.id, created_at: 3.weeks.ago) + let_it_be(:gitea_import_3) do + create(:project, import_type: 'gitea', creator_id: user.id, created_at: 19.days.ago) end - let_it_be(:old_import) { create(:project, import_type: 'gitea', creator_id: user.id, created_at: 2.months.ago) } + let_it_be(:bitbucket_import_1) do + create(:project, import_type: 'bitbucket', creator_id: user.id, created_at: 2.weeks.ago) + end + + let_it_be(:bitbucket_import_2) do + create(:project, import_type: 'bitbucket', creator_id: user.id, created_at: 1.week.ago) + end context 'with import_type gitea' do context 'with all time frame' do diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_total_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_total_metric_spec.rb new file mode 100644 index 00000000000..bfc4240def6 --- /dev/null +++ b/spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_total_metric_spec.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountImportedProjectsTotalMetric do + let_it_be(:user) { create(:user) } + let_it_be(:gitea_imports) do + create_list(:project, 3, import_type: 'gitea', creator_id: user.id, created_at: 3.weeks.ago) + end + + let_it_be(:bitbucket_imports) do + create_list(:project, 2, import_type: 'bitbucket', creator_id: user.id, created_at: 3.weeks.ago) + end + + let_it_be(:old_import) { create(:project, import_type: 'gitea', creator_id: user.id, created_at: 2.months.ago) } + + let_it_be(:bulk_import_projects) do + create_list(:bulk_import_entity, 3, source_type: 'project_entity', created_at: 3.weeks.ago) + end + + let_it_be(:bulk_import_groups) do + create_list(:bulk_import_entity, 3, source_type: 'group_entity', created_at: 3.weeks.ago) + end + + let_it_be(:old_bulk_import_project) do + create(:bulk_import_entity, source_type: 'project_entity', created_at: 2.months.ago) + end + + before do + allow(ApplicationRecord.connection).to receive(:transaction_open?).and_return(false) + end + + context 'with all time frame' do + let(:expected_value) { 10 } + let(:expected_query) do + "SELECT (SELECT COUNT(\"projects\".\"id\") FROM \"projects\" WHERE \"projects\".\"import_type\""\ + " IN ('gitlab_project', 'gitlab', 'github', 'bitbucket', 'bitbucket_server', 'gitea', 'git', 'manifest',"\ + " 'gitlab_migration'))"\ + " + (SELECT COUNT(\"bulk_import_entities\".\"id\") FROM \"bulk_import_entities\""\ + " WHERE \"bulk_import_entities\".\"source_type\" = 1)" + end + + it_behaves_like 'a correct instrumented metric value and query', time_frame: 'all' + end + + context 'for 28d time frame' do + let(:expected_value) { 8 } + let(:start) { 30.days.ago.to_s(:db) } + let(:finish) { 2.days.ago.to_s(:db) } + let(:expected_query) do + "SELECT (SELECT COUNT(\"projects\".\"id\") FROM \"projects\" WHERE \"projects\".\"import_type\""\ + " IN ('gitlab_project', 'gitlab', 'github', 'bitbucket', 'bitbucket_server', 'gitea', 'git', 'manifest',"\ + " 'gitlab_migration')"\ + " AND \"projects\".\"created_at\" BETWEEN '#{start}' AND '#{finish}')"\ + " + (SELECT COUNT(\"bulk_import_entities\".\"id\") FROM \"bulk_import_entities\""\ + " WHERE \"bulk_import_entities\".\"source_type\" = 1 AND \"bulk_import_entities\".\"created_at\""\ + " BETWEEN '#{start}' AND '#{finish}')" + end + + it_behaves_like 'a correct instrumented metric value and query', time_frame: '28d' + end +end diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/jira_imports_total_imported_issues_count_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/jira_imports_total_imported_issues_count_metric_spec.rb new file mode 100644 index 00000000000..f7a53cd3dcc --- /dev/null +++ b/spec/lib/gitlab/usage/metrics/instrumentations/jira_imports_total_imported_issues_count_metric_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Usage::Metrics::Instrumentations::JiraImportsTotalImportedIssuesCountMetric do + let_it_be(:jira_import_state_1) { create(:jira_import_state, :finished, imported_issues_count: 3) } + let_it_be(:jira_import_state_2) { create(:jira_import_state, :finished, imported_issues_count: 2) } + + let(:expected_value) { 5 } + let(:expected_query) do + 'SELECT SUM("jira_imports"."imported_issues_count") FROM "jira_imports" WHERE "jira_imports"."status" = 4' + end + + it_behaves_like 'a correct instrumented metric value and query', { time_frame: 'all' } +end diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/numbers_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/numbers_metric_spec.rb new file mode 100644 index 00000000000..180c76d56f3 --- /dev/null +++ b/spec/lib/gitlab/usage/metrics/instrumentations/numbers_metric_spec.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Usage::Metrics::Instrumentations::NumbersMetric do + subject do + described_class.tap do |metric_class| + metric_class.operation :add + metric_class.data do |time_frame| + [ + Gitlab::Usage::Metrics::Instrumentations::CountIssuesMetric.new(time_frame: time_frame).value, + Gitlab::Usage::Metrics::Instrumentations::CountBoardsMetric.new(time_frame: time_frame).value + ] + end + end.new(time_frame: 'all') + end + + describe '#value' do + let_it_be(:issue_1) { create(:issue) } + let_it_be(:issue_2) { create(:issue) } + let_it_be(:issue_3) { create(:issue) } + let_it_be(:issues) { Issue.all } + + let_it_be(:board_1) { create(:board) } + let_it_be(:boards) { Board.all } + + before do + allow(Issue.connection).to receive(:transaction_open?).and_return(false) + end + + it 'calculates a correct result' do + expect(subject.value).to eq(4) + end + + context 'with availability defined' do + subject do + described_class.tap do |metric_class| + metric_class.operation :add + metric_class.data { [1] } + metric_class.available? { false } + end.new(time_frame: 'all') + end + + it 'responds to #available? properly' do + expect(subject.available?).to eq(false) + end + end + + context 'with availability not defined' do + subject do + Class.new(described_class) do + operation :add + data { [] } + end.new(time_frame: 'all') + end + + it 'responds to #available? properly' do + expect(subject.available?).to eq(true) + end + end + end + + context 'with unimplemented operation method used' do + subject do + described_class.tap do |metric_class| + metric_class.operation :invalid_operation + metric_class.data { [] } + end.new(time_frame: 'all') + end + + it 'raises an error' do + expect { subject }.to raise_error(described_class::UnimplementedOperationError) + end + end +end diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/unique_active_users_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/unique_active_users_metric_spec.rb new file mode 100644 index 00000000000..8a0ce61de74 --- /dev/null +++ b/spec/lib/gitlab/usage/metrics/instrumentations/unique_active_users_metric_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Usage::Metrics::Instrumentations::UniqueActiveUsersMetric do + let_it_be(:user1) { create(:user, last_activity_on: 1.day.ago) } + let_it_be(:user2) { create(:user, last_activity_on: 5.days.ago) } + let_it_be(:user3) { create(:user, last_activity_on: 50.days.ago) } + let_it_be(:user4) { create(:user) } + let_it_be(:user5) { create(:user, user_type: 1, last_activity_on: 5.days.ago ) } # support bot + let_it_be(:user6) { create(:user, state: 'blocked') } + + context '28d' do + let(:start) { 30.days.ago.to_date.to_s } + let(:finish) { 2.days.ago.to_date.to_s } + let(:expected_value) { 1 } + let(:expected_query) do + "SELECT COUNT(\"users\".\"id\") FROM \"users\" WHERE (\"users\".\"state\" IN ('active')) AND " \ + "(\"users\".\"user_type\" IS NULL OR \"users\".\"user_type\" IN (6, 4)) AND \"users\".\"last_activity_on\" " \ + "BETWEEN '#{start}' AND '#{finish}'" + end + + it_behaves_like 'a correct instrumented metric value and query', { time_frame: '28d' } + end + + context 'all' do + let(:expected_value) { 4 } + + it_behaves_like 'a correct instrumented metric value', { time_frame: 'all' } + end +end diff --git a/spec/lib/gitlab/usage/metrics/name_suggestion_spec.rb b/spec/lib/gitlab/usage/metrics/name_suggestion_spec.rb index 6955fbcaf5a..9ee8bc6b568 100644 --- a/spec/lib/gitlab/usage/metrics/name_suggestion_spec.rb +++ b/spec/lib/gitlab/usage/metrics/name_suggestion_spec.rb @@ -71,9 +71,19 @@ RSpec.describe Gitlab::Usage::Metrics::NameSuggestion do end end + context 'for average metrics' do + it_behaves_like 'name suggestion' do + # corresponding metric is collected with average(Ci::Pipeline, :duration) + let(:key_path) { 'counts.ci_pipeline_duration' } + let(:operation) { :average } + let(:relation) { Ci::Pipeline } + let(:column) { :duration} + let(:name_suggestion) { /average_duration_from_ci_pipelines/ } + end + end + context 'for redis metrics' do it_behaves_like 'name suggestion' do - # corresponding metric is collected with redis_usage_data { unique_visit_service.unique_visits_for(targets: :analytics) } let(:operation) { :redis } let(:column) { nil } let(:relation) { nil } diff --git a/spec/lib/gitlab/usage/metrics/names_suggestions/generator_spec.rb b/spec/lib/gitlab/usage/metrics/names_suggestions/generator_spec.rb index f81ad9b193d..167dba9b57d 100644 --- a/spec/lib/gitlab/usage/metrics/names_suggestions/generator_spec.rb +++ b/spec/lib/gitlab/usage/metrics/names_suggestions/generator_spec.rb @@ -77,8 +77,7 @@ RSpec.describe Gitlab::Usage::Metrics::NamesSuggestions::Generator do context 'for redis metrics' do it_behaves_like 'name suggestion' do - # corresponding metric is collected with redis_usage_data { unique_visit_service.unique_visits_for(targets: :analytics) } - let(:key_path) { 'analytics_unique_visits.analytics_unique_visits_for_any_target' } + let(:key_path) { 'usage_activity_by_stage_monthly.create.merge_requests_users' } let(:name_suggestion) { /<please fill metric name, suggested format is: {subject}_{verb}{ing|ed}_{object} eg: users_creating_epics or merge_requests_viewed_in_single_file_mode>/ } end end diff --git a/spec/lib/gitlab/usage/metrics/query_spec.rb b/spec/lib/gitlab/usage/metrics/query_spec.rb index 65b8a7a046b..355d619f768 100644 --- a/spec/lib/gitlab/usage/metrics/query_spec.rb +++ b/spec/lib/gitlab/usage/metrics/query_spec.rb @@ -61,6 +61,12 @@ RSpec.describe Gitlab::Usage::Metrics::Query do end end + describe '.average' do + it 'returns the raw SQL' do + expect(described_class.for(:average, Issue, :weight)).to eq('SELECT AVG("issues"."weight") FROM "issues"') + end + end + describe 'estimate_batch_distinct_count' do it 'returns the raw SQL' do expect(described_class.for(:estimate_batch_distinct_count, Issue, :author_id)).to eq('SELECT COUNT(DISTINCT "issues"."author_id") FROM "issues"') diff --git a/spec/lib/gitlab/usage/service_ping_report_spec.rb b/spec/lib/gitlab/usage/service_ping_report_spec.rb index e007554df4a..1e8f9db4dea 100644 --- a/spec/lib/gitlab/usage/service_ping_report_spec.rb +++ b/spec/lib/gitlab/usage/service_ping_report_spec.rb @@ -155,6 +155,11 @@ RSpec.describe Gitlab::Usage::ServicePingReport, :use_clean_rails_memory_store_c memoized_constatns += Gitlab::UsageData::EE_MEMOIZED_VALUES if defined? Gitlab::UsageData::EE_MEMOIZED_VALUES memoized_constatns.each { |v| Gitlab::UsageData.clear_memoization(v) } stub_database_flavor_check('Cloud SQL for PostgreSQL') + + # in_product_marketing_email metrics values are extracted from a single group by query + # to check if the queries for individual metrics return the same value as group by when the value is non-zero + create(:in_product_marketing_email, track: :create, series: 0, cta_clicked_at: Time.current) + create(:in_product_marketing_email, track: :verify, series: 0) end let(:service_ping_payload) { described_class.for(output: :all_metrics_values) } |