summaryrefslogtreecommitdiff
path: root/spec/lib/gitlab/usage/metrics
diff options
context:
space:
mode:
Diffstat (limited to 'spec/lib/gitlab/usage/metrics')
-rw-r--r--spec/lib/gitlab/usage/metrics/aggregates/aggregate_spec.rb150
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/aggregated_metric_spec.rb72
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/distinct_count_projects_with_expiration_policy_disabled_metric_spec.rb19
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/gitlab_for_jira_app_direct_installations_count_metric_spec.rb18
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/gitlab_for_jira_app_proxy_installations_count_metric_spec.rb19
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/merge_request_widget_extension_metric_spec.rb25
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/redis_metric_spec.rb30
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/work_items_activity_aggregated_metric_spec.rb60
8 files changed, 386 insertions, 7 deletions
diff --git a/spec/lib/gitlab/usage/metrics/aggregates/aggregate_spec.rb b/spec/lib/gitlab/usage/metrics/aggregates/aggregate_spec.rb
index 8e02f4f562c..76eec2755df 100644
--- a/spec/lib/gitlab/usage/metrics/aggregates/aggregate_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/aggregates/aggregate_spec.rb
@@ -235,10 +235,27 @@ RSpec.describe Gitlab::Usage::Metrics::Aggregates::Aggregate, :clean_gitlab_redi
end
end
- it 'allows for YAML aliases in aggregated metrics configs' do
- expect(YAML).to receive(:safe_load).with(kind_of(String), aliases: true).at_least(:once)
+ context 'legacy aggregated metrics configuration' do
+ let(:temp_dir) { Dir.mktmpdir }
+ let(:temp_file) { Tempfile.new(%w[common .yml], temp_dir) }
+
+ before do
+ stub_const("#{namespace}::AGGREGATED_METRICS_PATH", File.expand_path('*.yml', temp_dir))
+ File.open(temp_file.path, "w+b") do |file|
+ file.write [aggregated_metric(name: "gmau_1", time_frame: '7d')].to_yaml
+ end
+ end
+
+ after do
+ temp_file.unlink
+ FileUtils.remove_entry(temp_dir) if Dir.exist?(temp_dir)
+ end
- described_class.new(recorded_at)
+ it 'allows for YAML aliases in aggregated metrics configs' do
+ expect(YAML).to receive(:safe_load).with(kind_of(String), aliases: true).at_least(:once)
+
+ described_class.new(recorded_at)
+ end
end
describe '.aggregated_metrics_weekly_data' do
@@ -260,5 +277,132 @@ RSpec.describe Gitlab::Usage::Metrics::Aggregates::Aggregate, :clean_gitlab_redi
it_behaves_like 'database_sourced_aggregated_metrics'
it_behaves_like 'redis_sourced_aggregated_metrics'
end
+
+ describe '.calculate_count_for_aggregation' do
+ using RSpec::Parameterized::TableSyntax
+
+ context 'with valid configuration' do
+ where(:number_of_days, :operator, :datasource, :expected_method) do
+ 28 | 'AND' | 'redis' | :calculate_metrics_intersections
+ 7 | 'AND' | 'redis' | :calculate_metrics_intersections
+ 28 | 'AND' | 'database' | :calculate_metrics_intersections
+ 7 | 'AND' | 'database' | :calculate_metrics_intersections
+ 28 | 'OR' | 'redis' | :calculate_metrics_union
+ 7 | 'OR' | 'redis' | :calculate_metrics_union
+ 28 | 'OR' | 'database' | :calculate_metrics_union
+ 7 | 'OR' | 'database' | :calculate_metrics_union
+ end
+
+ with_them do
+ let(:time_frame) { "#{number_of_days}d" }
+ let(:start_date) { number_of_days.days.ago.to_date }
+ let(:params) { { start_date: start_date, end_date: end_date, recorded_at: recorded_at } }
+ let(:aggregate) do
+ {
+ source: datasource,
+ operator: operator,
+ events: %w[event1 event2]
+ }
+ end
+
+ subject(:calculate_count_for_aggregation) do
+ described_class
+ .new(recorded_at)
+ .calculate_count_for_aggregation(aggregation: aggregate, time_frame: time_frame)
+ end
+
+ it 'returns the number of unique events for aggregation', :aggregate_failures do
+ expect(namespace::SOURCES[datasource])
+ .to receive(expected_method)
+ .with(params.merge(metric_names: %w[event1 event2]))
+ .and_return(5)
+ expect(calculate_count_for_aggregation).to eq(5)
+ end
+ end
+ end
+
+ context 'with invalid configuration' do
+ where(:time_frame, :operator, :datasource, :expected_error) do
+ '28d' | 'SUM' | 'redis' | namespace::UnknownAggregationOperator
+ '7d' | 'AND' | 'mongodb' | namespace::UnknownAggregationSource
+ 'all' | 'AND' | 'redis' | namespace::DisallowedAggregationTimeFrame
+ end
+
+ with_them do
+ let(:aggregate) do
+ {
+ source: datasource,
+ operator: operator,
+ events: %w[event1 event2]
+ }
+ end
+
+ subject(:calculate_count_for_aggregation) do
+ described_class
+ .new(recorded_at)
+ .calculate_count_for_aggregation(aggregation: aggregate, time_frame: time_frame)
+ end
+
+ context 'with non prod environment' do
+ it 'raises error' do
+ expect { calculate_count_for_aggregation }.to raise_error expected_error
+ end
+ end
+
+ context 'with prod environment' do
+ before do
+ stub_rails_env('production')
+ end
+
+ it 'returns fallback value' do
+ expect(calculate_count_for_aggregation).to be(-1)
+ end
+ end
+ end
+ end
+
+ context 'when union data is not available' do
+ subject(:calculate_count_for_aggregation) do
+ described_class
+ .new(recorded_at)
+ .calculate_count_for_aggregation(aggregation: aggregate, time_frame: time_frame)
+ end
+
+ where(:time_frame, :operator, :datasource) do
+ '28d' | 'OR' | 'redis'
+ '7d' | 'OR' | 'database'
+ end
+
+ with_them do
+ before do
+ allow(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).and_raise(sources::UnionNotAvailable)
+ end
+
+ let(:aggregate) do
+ {
+ source: datasource,
+ operator: operator,
+ events: %w[event1 event2]
+ }
+ end
+
+ context 'with non prod environment' do
+ it 'raises error' do
+ expect { calculate_count_for_aggregation }.to raise_error sources::UnionNotAvailable
+ end
+ end
+
+ context 'with prod environment' do
+ before do
+ stub_rails_env('production')
+ end
+
+ it 'returns fallback value' do
+ expect(calculate_count_for_aggregation).to be(-1)
+ end
+ end
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/aggregated_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/aggregated_metric_spec.rb
new file mode 100644
index 00000000000..3e7b13e21c1
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/aggregated_metric_spec.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::AggregatedMetric, :clean_gitlab_redis_shared_state do
+ using RSpec::Parameterized::TableSyntax
+ before do
+ # weekly AND 1 weekly OR 2
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:i_quickactions_approve, values: 1, time: 1.week.ago)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:i_quickactions_unapprove, values: 1, time: 1.week.ago)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:i_quickactions_unapprove, values: 2, time: 1.week.ago)
+
+ # monthly AND 2 weekly OR 3
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:i_quickactions_approve, values: 2, time: 2.weeks.ago)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:i_quickactions_unapprove, values: 3, time: 2.weeks.ago)
+
+ # out of date range
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:i_quickactions_approve, values: 3, time: 2.months.ago)
+
+ # database events
+ Gitlab::Usage::Metrics::Aggregates::Sources::PostgresHll
+ .save_aggregated_metrics(
+ metric_name: :i_quickactions_approve,
+ time_period: { created_at: (1.week.ago..Date.current) },
+ recorded_at_timestamp: Time.current,
+ data: ::Gitlab::Database::PostgresHll::Buckets.new(141 => 1, 56 => 1)
+ )
+ Gitlab::Usage::Metrics::Aggregates::Sources::PostgresHll
+ .save_aggregated_metrics(
+ metric_name: :i_quickactions_unapprove,
+ time_period: { created_at: (1.week.ago..Date.current) },
+ recorded_at_timestamp: Time.current,
+ data: ::Gitlab::Database::PostgresHll::Buckets.new(10 => 1, 56 => 1)
+ )
+ end
+
+ where(:data_source, :time_frame, :operator, :expected_value) do
+ 'redis_hll' | '28d' | 'AND' | 2
+ 'redis_hll' | '28d' | 'OR' | 3
+ 'redis_hll' | '7d' | 'AND' | 1
+ 'redis_hll' | '7d' | 'OR' | 2
+ 'database' | '7d' | 'OR' | 3.0
+ 'database' | '7d' | 'AND' | 1.0
+ end
+
+ with_them do
+ let(:error_rate) { Gitlab::Database::PostgresHll::BatchDistinctCounter::ERROR_RATE }
+ let(:metric_definition) do
+ {
+ data_source: data_source,
+ time_frame: time_frame,
+ options: {
+ aggregate: {
+ operator: operator
+ },
+ events: %w[
+ i_quickactions_approve
+ i_quickactions_unapprove
+ ]
+ }
+ }
+ end
+
+ around do |example|
+ freeze_time { example.run }
+ end
+
+ it 'has correct value' do
+ expect(described_class.new(metric_definition).value).to be_within(error_rate).percent_of(expected_value)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/distinct_count_projects_with_expiration_policy_disabled_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/distinct_count_projects_with_expiration_policy_disabled_metric_spec.rb
new file mode 100644
index 00000000000..757adee6117
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/distinct_count_projects_with_expiration_policy_disabled_metric_spec.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DistinctCountProjectsWithExpirationPolicyDisabledMetric do
+ before_all do
+ create(:container_expiration_policy, enabled: false)
+ create(:container_expiration_policy, enabled: false, created_at: 29.days.ago)
+ create(:container_expiration_policy, enabled: true)
+ end
+
+ it_behaves_like 'a correct instrumented metric value', { time_frame: '28d' } do
+ let(:expected_value) { 1 }
+ end
+
+ it_behaves_like 'a correct instrumented metric value', { time_frame: 'all' } do
+ let(:expected_value) { 2 }
+ end
+end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/gitlab_for_jira_app_direct_installations_count_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/gitlab_for_jira_app_direct_installations_count_metric_spec.rb
new file mode 100644
index 00000000000..061558085a1
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/gitlab_for_jira_app_direct_installations_count_metric_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::GitlabForJiraAppDirectInstallationsCountMetric do
+ before do
+ create(:jira_connect_subscription)
+ end
+
+ let(:expected_value) { 1 }
+ let(:expected_query) do
+ 'SELECT COUNT("jira_connect_installations"."id") FROM "jira_connect_installations"'\
+ ' INNER JOIN "jira_connect_subscriptions" ON "jira_connect_subscriptions"."jira_connect_installation_id"'\
+ ' = "jira_connect_installations"."id"'
+ end
+
+ it_behaves_like 'a correct instrumented metric value and query', { time_frame: 'all' }
+end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/gitlab_for_jira_app_proxy_installations_count_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/gitlab_for_jira_app_proxy_installations_count_metric_spec.rb
new file mode 100644
index 00000000000..4535bab7702
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/gitlab_for_jira_app_proxy_installations_count_metric_spec.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::GitlabForJiraAppProxyInstallationsCountMetric do
+ let_it_be(:installation) { create(:jira_connect_installation, instance_url: 'http://self-managed-gitlab.com') }
+
+ before do
+ create(:jira_connect_subscription, installation: installation)
+ end
+
+ let(:expected_value) { 1 }
+ let(:expected_query) do
+ 'SELECT COUNT("jira_connect_installations"."id") FROM "jira_connect_installations"'\
+ ' WHERE "jira_connect_installations"."instance_url" IS NOT NULL'
+ end
+
+ it_behaves_like 'a correct instrumented metric value and query', { time_frame: 'all' }
+end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/merge_request_widget_extension_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/merge_request_widget_extension_metric_spec.rb
new file mode 100644
index 00000000000..c0ac00c9cdd
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/merge_request_widget_extension_metric_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::MergeRequestWidgetExtensionMetric,
+ :clean_gitlab_redis_shared_state do
+ before do
+ 4.times do
+ Gitlab::UsageDataCounters::MergeRequestWidgetExtensionCounter.count(:terraform_count_expand)
+ end
+ end
+
+ let(:expected_value) { 4 }
+
+ it_behaves_like 'a correct instrumented metric value', {
+ options: { event: 'expand', widget: 'terraform' },
+ time_frame: 'all'
+ }
+
+ it 'raises an exception if widget option is not present' do
+ expect do
+ described_class.new(options: { event: 'expand' }, time_frame: 'all')
+ end.to raise_error(ArgumentError, /'widget' option is required/)
+ end
+end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/redis_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/redis_metric_spec.rb
index 80ae5c6fd21..c4d6edd43e1 100644
--- a/spec/lib/gitlab/usage/metrics/instrumentations/redis_metric_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/redis_metric_spec.rb
@@ -11,14 +11,21 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::RedisMetric, :clean_git
let(:expected_value) { 4 }
- it_behaves_like 'a correct instrumented metric value', { options: { event: 'pushes', prefix: 'source_code' } }
+ it_behaves_like 'a correct instrumented metric value', {
+ options: { event: 'pushes', prefix: 'source_code' },
+ time_frame: 'all'
+ }
it 'raises an exception if event option is not present' do
- expect { described_class.new(prefix: 'source_code') }.to raise_error(ArgumentError)
+ expect do
+ described_class.new(options: { prefix: 'source_code' }, time_frame: 'all')
+ end.to raise_error(ArgumentError, /'event' option is required/)
end
it 'raises an exception if prefix option is not present' do
- expect { described_class.new(event: 'pushes') }.to raise_error(ArgumentError)
+ expect do
+ described_class.new(options: { event: 'pushes' }, time_frame: 'all')
+ end.to raise_error(ArgumentError, /'prefix' option is required/)
end
describe 'children classes' do
@@ -55,7 +62,22 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::RedisMetric, :clean_git
end
it_behaves_like 'a correct instrumented metric value', {
- options: { event: 'merge_requests_count', prefix: 'web_ide', include_usage_prefix: false }
+ options: { event: 'merge_requests_count', prefix: 'web_ide', include_usage_prefix: false },
+ time_frame: 'all'
+ }
+ end
+
+ context "with prefix disabled" do
+ let(:expected_value) { 3 }
+
+ before do
+ 3.times do
+ Gitlab::UsageDataCounters::SearchCounter.count(:all_searches)
+ end
+ end
+
+ it_behaves_like 'a correct instrumented metric value', {
+ options: { event: 'all_searches_count', prefix: nil, include_usage_prefix: false }, time_frame: 'all'
}
end
end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/work_items_activity_aggregated_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/work_items_activity_aggregated_metric_spec.rb
new file mode 100644
index 00000000000..3e315692d0a
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/work_items_activity_aggregated_metric_spec.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::WorkItemsActivityAggregatedMetric do
+ let(:metric_definition) do
+ {
+ data_source: 'redis_hll',
+ time_frame: time_frame,
+ options: {
+ aggregate: {
+ operator: 'OR'
+ },
+ events: %w[
+ users_creating_work_items
+ users_updating_work_item_title
+ users_updating_work_item_dates
+ users_updating_work_item_iteration
+ ]
+ }
+ }
+ end
+
+ around do |example|
+ freeze_time { example.run }
+ end
+
+ where(:time_frame) { [['28d'], ['7d']] }
+
+ with_them do
+ describe '#available?' do
+ it 'returns false without track_work_items_activity feature' do
+ stub_feature_flags(track_work_items_activity: false)
+
+ expect(described_class.new(metric_definition).available?).to eq(false)
+ end
+
+ it 'returns true with track_work_items_activity feature' do
+ stub_feature_flags(track_work_items_activity: true)
+
+ expect(described_class.new(metric_definition).available?).to eq(true)
+ end
+ end
+
+ describe '#value', :clean_gitlab_redis_shared_state do
+ let(:counter) { Gitlab::UsageDataCounters::HLLRedisCounter }
+
+ before do
+ counter.track_event(:users_creating_work_items, values: 1, time: 1.week.ago)
+ counter.track_event(:users_updating_work_item_title, values: 1, time: 1.week.ago)
+ counter.track_event(:users_updating_work_item_dates, values: 2, time: 1.week.ago)
+ counter.track_event(:users_updating_work_item_iteration, values: 2, time: 1.week.ago)
+ end
+
+ it 'has correct value' do
+ expect(described_class.new(metric_definition).value).to eq 2
+ end
+ end
+ end
+end