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:
Diffstat (limited to 'spec/lib/gitlab/usage')
-rw-r--r--spec/lib/gitlab/usage/metric_definition_spec.rb16
-rw-r--r--spec/lib/gitlab/usage/metrics/aggregates/aggregate_spec.rb105
-rw-r--r--spec/lib/gitlab/usage/metrics/aggregates/sources/calculations/intersection_spec.rb89
-rw-r--r--spec/lib/gitlab/usage/metrics/aggregates/sources/postgres_hll_spec.rb60
-rw-r--r--spec/lib/gitlab/usage/metrics/aggregates/sources/redis_hll_spec.rb35
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/count_boards_metric_spec.rb9
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/count_issues_metric_spec.rb9
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/count_users_creating_issues_metric_spec.rb17
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/count_users_using_approve_quick_action_metric_spec.rb15
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/hostname_metric_spec.rb7
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/uuid_metric_spec.rb7
-rw-r--r--spec/lib/gitlab/usage/metrics/key_path_processor_spec.rb23
12 files changed, 282 insertions, 110 deletions
diff --git a/spec/lib/gitlab/usage/metric_definition_spec.rb b/spec/lib/gitlab/usage/metric_definition_spec.rb
index e99d720058a..92e51b8ea23 100644
--- a/spec/lib/gitlab/usage/metric_definition_spec.rb
+++ b/spec/lib/gitlab/usage/metric_definition_spec.rb
@@ -25,6 +25,12 @@ RSpec.describe Gitlab::Usage::MetricDefinition do
let(:definition) { described_class.new(path, attributes) }
let(:yaml_content) { attributes.deep_stringify_keys.to_yaml }
+ around do |example|
+ described_class.instance_variable_set(:@definitions, nil)
+ example.run
+ described_class.instance_variable_set(:@definitions, nil)
+ end
+
def write_metric(metric, path, content)
path = File.join(metric, path)
dir = File.dirname(path)
@@ -32,6 +38,11 @@ RSpec.describe Gitlab::Usage::MetricDefinition do
File.write(path, content)
end
+ after do
+ # Reset memoized `definitions` result
+ described_class.instance_variable_set(:@definitions, nil)
+ end
+
it 'has all definitons valid' do
expect { described_class.definitions }.not_to raise_error(Gitlab::Usage::Metric::InvalidMetricError)
end
@@ -62,6 +73,9 @@ RSpec.describe Gitlab::Usage::MetricDefinition do
:distribution | 'test'
:tier | %w(test ee)
:name | 'count_<adjective_describing>_boards'
+
+ :instrumentation_class | 'Metric_Class'
+ :instrumentation_class | 'metricClass'
end
with_them do
@@ -184,8 +198,6 @@ RSpec.describe Gitlab::Usage::MetricDefinition do
File.join(metric2, '**', '*.yml')
]
)
- # Reset memoized `definitions` result
- described_class.instance_variable_set(:@definitions, nil)
end
after do
diff --git a/spec/lib/gitlab/usage/metrics/aggregates/aggregate_spec.rb b/spec/lib/gitlab/usage/metrics/aggregates/aggregate_spec.rb
index 7d8e3056384..0fb3a69df05 100644
--- a/spec/lib/gitlab/usage/metrics/aggregates/aggregate_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/aggregates/aggregate_spec.rb
@@ -65,76 +65,35 @@ RSpec.describe Gitlab::Usage::Metrics::Aggregates::Aggregate, :clean_gitlab_redi
end
context 'there are aggregated metrics defined' do
+ let(:aggregated_metrics) do
+ [
+ aggregated_metric(name: "gmau_1", source: datasource, time_frame: time_frame, operator: operator)
+ ]
+ end
+
+ let(:results) { { 'gmau_1' => 5 } }
+ let(:params) { { start_date: start_date, end_date: end_date, recorded_at: recorded_at } }
+
before do
allow_next_instance_of(described_class) do |instance|
allow(instance).to receive(:aggregated_metrics).and_return(aggregated_metrics)
end
end
- context 'with AND operator' do
- let(:aggregated_metrics) do
- params = { source: datasource, operator: "AND", time_frame: time_frame }
- [
- aggregated_metric(**params.merge(name: "gmau_1", events: %w[event3 event5])),
- aggregated_metric(**params.merge(name: "gmau_2"))
- ]
- end
-
- it 'returns the number of unique events recorded for every metric in aggregate', :aggregate_failures do
- results = {
- 'gmau_1' => 2,
- 'gmau_2' => 1
- }
- params = { start_date: start_date, end_date: end_date, recorded_at: recorded_at }
-
- # gmau_1 data is as follow
- # |A| => 4
- expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: 'event3')).and_return(4)
- # |B| => 6
- expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: 'event5')).and_return(6)
- # |A + B| => 8
- expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event3 event5])).and_return(8)
- # Exclusion inclusion principle formula to calculate intersection of 2 sets
- # |A & B| = (|A| + |B|) - |A + B| => (4 + 6) - 8 => 2
-
- # gmau_2 data is as follow:
- # |A| => 2
- expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: 'event1')).and_return(2)
- # |B| => 3
- expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: 'event2')).and_return(3)
- # |C| => 5
- expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: 'event3')).and_return(5)
-
- # |A + B| => 4 therefore |A & B| = (|A| + |B|) - |A + B| => 2 + 3 - 4 => 1
- expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event1 event2])).and_return(4)
- # |A + C| => 6 therefore |A & C| = (|A| + |C|) - |A + C| => 2 + 5 - 6 => 1
- expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event1 event3])).and_return(6)
- # |B + C| => 7 therefore |B & C| = (|B| + |C|) - |B + C| => 3 + 5 - 7 => 1
- expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event2 event3])).and_return(7)
- # |A + B + C| => 8
- expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event1 event2 event3])).and_return(8)
- # Exclusion inclusion principle formula to calculate intersection of 3 sets
- # |A & B & C| = (|A & B| + |A & C| + |B & C|) - (|A| + |B| + |C|) + |A + B + C|
- # (1 + 1 + 1) - (2 + 3 + 5) + 8 => 1
+ context 'with OR operator' do
+ let(:operator) { Gitlab::Usage::Metrics::Aggregates::UNION_OF_AGGREGATED_METRICS }
+ it 'returns the number of unique events occurred for any metric in aggregate', :aggregate_failures do
+ expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event1 event2 event3])).and_return(5)
expect(aggregated_metrics_data).to eq(results)
end
end
- context 'with OR operator' do
- let(:aggregated_metrics) do
- [
- aggregated_metric(name: "gmau_1", source: datasource, time_frame: time_frame, operator: "OR")
- ]
- end
-
- it 'returns the number of unique events occurred for any metric in aggregate', :aggregate_failures do
- results = {
- 'gmau_1' => 5
- }
- params = { start_date: start_date, end_date: end_date, recorded_at: recorded_at }
+ context 'with AND operator' do
+ let(:operator) { Gitlab::Usage::Metrics::Aggregates::INTERSECTION_OF_AGGREGATED_METRICS }
- expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event1 event2 event3])).and_return(5)
+ it 'returns the number of unique events that occurred for all of metrics in the aggregate', :aggregate_failures do
+ expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_intersections).with(params.merge(metric_names: %w[event1 event2 event3])).and_return(5)
expect(aggregated_metrics_data).to eq(results)
end
end
@@ -331,36 +290,6 @@ RSpec.describe Gitlab::Usage::Metrics::Aggregates::Aggregate, :clean_gitlab_redi
it_behaves_like 'database_sourced_aggregated_metrics'
it_behaves_like 'redis_sourced_aggregated_metrics'
it_behaves_like 'db sourced aggregated metrics without database_sourced_aggregated_metrics feature'
-
- context 'metrics union calls' do
- it 'caches intermediate operations', :aggregate_failures do
- events = %w[event1 event2 event3 event5]
- allow_next_instance_of(described_class) do |instance|
- allow(instance).to receive(:aggregated_metrics)
- .and_return([aggregated_metric(name: 'gmau_1', events: events, operator: "AND", time_frame: time_frame)])
- end
-
- params = { start_date: start_date, end_date: end_date, recorded_at: recorded_at }
-
- events.each do |event|
- expect(sources::RedisHll).to receive(:calculate_metrics_union)
- .with(params.merge(metric_names: event))
- .once
- .and_return(0)
- end
-
- 2.upto(4) do |subset_size|
- events.combination(subset_size).each do |events|
- expect(sources::RedisHll).to receive(:calculate_metrics_union)
- .with(params.merge(metric_names: events))
- .once
- .and_return(0)
- end
- end
-
- aggregated_metrics_data
- end
- end
end
end
end
diff --git a/spec/lib/gitlab/usage/metrics/aggregates/sources/calculations/intersection_spec.rb b/spec/lib/gitlab/usage/metrics/aggregates/sources/calculations/intersection_spec.rb
new file mode 100644
index 00000000000..41cb445155e
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/aggregates/sources/calculations/intersection_spec.rb
@@ -0,0 +1,89 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Aggregates::Sources::Calculations::Intersection do
+ let_it_be(:recorded_at) { Time.current.to_i }
+ let_it_be(:start_date) { 4.weeks.ago.to_date }
+ let_it_be(:end_date) { Date.current }
+
+ shared_examples 'aggregated_metrics_data with source' do
+ context 'with AND operator' do
+ let(:params) { { start_date: start_date, end_date: end_date, recorded_at: recorded_at } }
+
+ context 'with even number of metrics' do
+ it 'calculates intersection correctly', :aggregate_failures do
+ # gmau_1 data is as follow
+ # |A| => 4
+ expect(source).to receive(:calculate_metrics_union).with(params.merge(metric_names: 'event3')).and_return(4)
+ # |B| => 6
+ expect(source).to receive(:calculate_metrics_union).with(params.merge(metric_names: 'event5')).and_return(6)
+ # |A + B| => 8
+ expect(source).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event3 event5])).and_return(8)
+ # Exclusion inclusion principle formula to calculate intersection of 2 sets
+ # |A & B| = (|A| + |B|) - |A + B| => (4 + 6) - 8 => 2
+ expect(source.calculate_metrics_intersections(metric_names: %w[event3 event5], start_date: start_date, end_date: end_date, recorded_at: recorded_at)).to eq(2)
+ end
+ end
+
+ context 'with odd number of metrics' do
+ it 'calculates intersection correctly', :aggregate_failures do
+ # gmau_2 data is as follow:
+ # |A| => 2
+ expect(source).to receive(:calculate_metrics_union).with(params.merge(metric_names: 'event1')).and_return(2)
+ # |B| => 3
+ expect(source).to receive(:calculate_metrics_union).with(params.merge(metric_names: 'event2')).and_return(3)
+ # |C| => 5
+ expect(source).to receive(:calculate_metrics_union).with(params.merge(metric_names: 'event3')).and_return(5)
+
+ # |A + B| => 4 therefore |A & B| = (|A| + |B|) - |A + B| => 2 + 3 - 4 => 1
+ expect(source).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event1 event2])).and_return(4)
+ # |A + C| => 6 therefore |A & C| = (|A| + |C|) - |A + C| => 2 + 5 - 6 => 1
+ expect(source).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event1 event3])).and_return(6)
+ # |B + C| => 7 therefore |B & C| = (|B| + |C|) - |B + C| => 3 + 5 - 7 => 1
+ expect(source).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event2 event3])).and_return(7)
+ # |A + B + C| => 8
+ expect(source).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event1 event2 event3])).and_return(8)
+ # Exclusion inclusion principle formula to calculate intersection of 3 sets
+ # |A & B & C| = (|A & B| + |A & C| + |B & C|) - (|A| + |B| + |C|) + |A + B + C|
+ # (1 + 1 + 1) - (2 + 3 + 5) + 8 => 1
+ expect(source.calculate_metrics_intersections(metric_names: %w[event1 event2 event3], start_date: start_date, end_date: end_date, recorded_at: recorded_at)).to eq(1)
+ end
+ end
+ end
+ end
+
+ describe '.aggregated_metrics_data' do
+ let(:source) do
+ Class.new do
+ extend Gitlab::Usage::Metrics::Aggregates::Sources::Calculations::Intersection
+ end
+ end
+
+ it 'caches intermediate operations', :aggregate_failures do
+ events = %w[event1 event2 event3 event5]
+
+ params = { start_date: start_date, end_date: end_date, recorded_at: recorded_at }
+
+ events.each do |event|
+ expect(source).to receive(:calculate_metrics_union)
+ .with(params.merge(metric_names: event))
+ .once
+ .and_return(0)
+ end
+
+ 2.upto(4) do |subset_size|
+ events.combination(subset_size).each do |events|
+ expect(source).to receive(:calculate_metrics_union)
+ .with(params.merge(metric_names: events))
+ .once
+ .and_return(0)
+ end
+ end
+
+ expect(source.calculate_metrics_intersections(metric_names: events, start_date: start_date, end_date: end_date, recorded_at: recorded_at)).to eq(0)
+ end
+
+ it_behaves_like 'aggregated_metrics_data with source'
+ end
+end
diff --git a/spec/lib/gitlab/usage/metrics/aggregates/sources/postgres_hll_spec.rb b/spec/lib/gitlab/usage/metrics/aggregates/sources/postgres_hll_spec.rb
index db878828cd6..1ae4c9414dd 100644
--- a/spec/lib/gitlab/usage/metrics/aggregates/sources/postgres_hll_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/aggregates/sources/postgres_hll_spec.rb
@@ -12,11 +12,7 @@ RSpec.describe Gitlab::Usage::Metrics::Aggregates::Sources::PostgresHll, :clean_
let(:metric_2) { 'metric_2' }
let(:metric_names) { [metric_1, metric_2] }
- describe '.calculate_events_union' do
- subject(:calculate_metrics_union) do
- described_class.calculate_metrics_union(metric_names: metric_names, start_date: start_date, end_date: end_date, recorded_at: recorded_at)
- end
-
+ describe 'metric calculations' do
before do
[
{
@@ -36,23 +32,55 @@ RSpec.describe Gitlab::Usage::Metrics::Aggregates::Sources::PostgresHll, :clean_
end
end
- it 'returns the number of unique events in the union of all metrics' do
- expect(calculate_metrics_union.round(2)).to eq(3.12)
- end
+ describe '.calculate_events_union' do
+ subject(:calculate_metrics_union) do
+ described_class.calculate_metrics_union(metric_names: metric_names, start_date: start_date, end_date: end_date, recorded_at: recorded_at)
+ end
+
+ it 'returns the number of unique events in the union of all metrics' do
+ expect(calculate_metrics_union.round(2)).to eq(3.12)
+ end
+
+ context 'when there is no aggregated data saved' do
+ let(:metric_names) { [metric_1, 'i do not have any records'] }
+
+ it 'raises error when union data is missing' do
+ expect { calculate_metrics_union }.to raise_error Gitlab::Usage::Metrics::Aggregates::Sources::UnionNotAvailable
+ end
+ end
- context 'when there is no aggregated data saved' do
- let(:metric_names) { [metric_1, 'i do not have any records'] }
+ context 'when there is only one metric defined as aggregated' do
+ let(:metric_names) { [metric_1] }
- it 'raises error when union data is missing' do
- expect { calculate_metrics_union }.to raise_error Gitlab::Usage::Metrics::Aggregates::Sources::UnionNotAvailable
+ it 'returns the number of unique events for that metric' do
+ expect(calculate_metrics_union.round(2)).to eq(2.08)
+ end
end
end
- context 'when there is only one metric defined as aggregated' do
- let(:metric_names) { [metric_1] }
+ describe '.calculate_metrics_intersections' do
+ subject(:calculate_metrics_intersections) do
+ described_class.calculate_metrics_intersections(metric_names: metric_names, start_date: start_date, end_date: end_date, recorded_at: recorded_at)
+ end
+
+ it 'returns the number of common events in the intersection of all metrics' do
+ expect(calculate_metrics_intersections.round(2)).to eq(1.04)
+ end
+
+ context 'when there is no aggregated data saved' do
+ let(:metric_names) { [metric_1, 'i do not have any records'] }
- it 'returns the number of unique events for that metric' do
- expect(calculate_metrics_union.round(2)).to eq(2.08)
+ it 'raises error when union data is missing' do
+ expect { calculate_metrics_intersections }.to raise_error Gitlab::Usage::Metrics::Aggregates::Sources::UnionNotAvailable
+ end
+ end
+
+ context 'when there is only one metric defined in aggregate' do
+ let(:metric_names) { [metric_1] }
+
+ it 'returns the number of common/unique events for the intersection of that metric' do
+ expect(calculate_metrics_intersections.round(2)).to eq(2.08)
+ end
end
end
end
diff --git a/spec/lib/gitlab/usage/metrics/aggregates/sources/redis_hll_spec.rb b/spec/lib/gitlab/usage/metrics/aggregates/sources/redis_hll_spec.rb
index af2de5ea343..83b155b41b1 100644
--- a/spec/lib/gitlab/usage/metrics/aggregates/sources/redis_hll_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/aggregates/sources/redis_hll_spec.rb
@@ -3,11 +3,12 @@
require 'spec_helper'
RSpec.describe Gitlab::Usage::Metrics::Aggregates::Sources::RedisHll do
- describe '.calculate_events_union' do
- let(:event_names) { %w[event_a event_b] }
- let(:start_date) { 7.days.ago }
- let(:end_date) { Date.current }
+ let_it_be(:event_names) { %w[event_a event_b] }
+ let_it_be(:start_date) { 7.days.ago }
+ let_it_be(:end_date) { Date.current }
+ let_it_be(:recorded_at) { Time.current }
+ describe '.calculate_events_union' do
subject(:calculate_metrics_union) do
described_class.calculate_metrics_union(metric_names: event_names, start_date: start_date, end_date: end_date, recorded_at: nil)
end
@@ -26,4 +27,30 @@ RSpec.describe Gitlab::Usage::Metrics::Aggregates::Sources::RedisHll do
expect { calculate_metrics_union }.to raise_error Gitlab::Usage::Metrics::Aggregates::Sources::UnionNotAvailable
end
end
+
+ describe '.calculate_metrics_intersections' do
+ subject(:calculate_metrics_intersections) do
+ described_class.calculate_metrics_intersections(metric_names: event_names, start_date: start_date, end_date: end_date, recorded_at: recorded_at)
+ end
+
+ it 'uses values returned by union to compute the intersection' do
+ event_names.each do |event|
+ expect(Gitlab::Usage::Metrics::Aggregates::Sources::RedisHll).to receive(:calculate_metrics_union)
+ .with(metric_names: event, start_date: start_date, end_date: end_date, recorded_at: recorded_at)
+ .and_return(5)
+ end
+
+ expect(Gitlab::Usage::Metrics::Aggregates::Sources::RedisHll).to receive(:calculate_metrics_union)
+ .with(metric_names: event_names, start_date: start_date, end_date: end_date, recorded_at: recorded_at)
+ .and_return(2)
+
+ expect(calculate_metrics_intersections).to eq(8)
+ end
+
+ it 'raises error if union is < 0' do
+ allow(Gitlab::Usage::Metrics::Aggregates::Sources::RedisHll).to receive(:calculate_metrics_union).and_raise(Gitlab::Usage::Metrics::Aggregates::Sources::UnionNotAvailable)
+
+ expect { calculate_metrics_intersections }.to raise_error(Gitlab::Usage::Metrics::Aggregates::Sources::UnionNotAvailable)
+ end
+ end
end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/count_boards_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/count_boards_metric_spec.rb
new file mode 100644
index 00000000000..52c1ccdcd47
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/count_boards_metric_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountBoardsMetric do
+ let_it_be(:board) { create(:board) }
+
+ it_behaves_like 'a correct instrumented metric value', { time_frame: 'all', data_source: 'database' }, 1
+end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/count_issues_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/count_issues_metric_spec.rb
new file mode 100644
index 00000000000..c3b59904f41
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/count_issues_metric_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountIssuesMetric do
+ let_it_be(:issue) { create(:issue) }
+
+ it_behaves_like 'a correct instrumented metric value', { time_frame: 'all', data_source: 'database' }, 1
+end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/count_users_creating_issues_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/count_users_creating_issues_metric_spec.rb
new file mode 100644
index 00000000000..9f4686ab6cd
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/count_users_creating_issues_metric_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountUsersCreatingIssuesMetric do
+ let_it_be(:author) { create(:user) }
+ let_it_be(:issues) { create_list(:issue, 2, author: author, created_at: 4.days.ago) }
+ let_it_be(:old_issue) { create(:issue, author: author, created_at: 2.months.ago) }
+
+ context 'with all time frame' do
+ it_behaves_like 'a correct instrumented metric value', { time_frame: 'all', data_source: 'database' }, 1
+ end
+
+ context 'for 28d time frame' do
+ it_behaves_like 'a correct instrumented metric value', { time_frame: '28d', data_source: 'database' }, 1
+ end
+end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/count_users_using_approve_quick_action_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/count_users_using_approve_quick_action_metric_spec.rb
new file mode 100644
index 00000000000..7adba825a13
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/count_users_using_approve_quick_action_metric_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountUsersUsingApproveQuickActionMetric, :clean_gitlab_redis_shared_state do
+ before do
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:i_quickactions_approve, values: 1, time: 1.week.ago)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:i_quickactions_approve, values: 1, time: 2.weeks.ago)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:i_quickactions_approve, values: 2, time: 2.weeks.ago)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(:i_quickactions_approve, values: 2, time: 2.months.ago)
+ end
+
+ it_behaves_like 'a correct instrumented metric value', { time_frame: '28d', data_source: 'redis_hll' }, 2
+ it_behaves_like 'a correct instrumented metric value', { time_frame: '7d', data_source: 'redis_hll' }, 1
+end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/hostname_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/hostname_metric_spec.rb
new file mode 100644
index 00000000000..83e07200025
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/hostname_metric_spec.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::HostnameMetric do
+ it_behaves_like 'a correct instrumented metric value', { time_frame: 'none', data_source: 'ruby' }, Gitlab.config.gitlab.host
+end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/uuid_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/uuid_metric_spec.rb
new file mode 100644
index 00000000000..212dd3dc851
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/uuid_metric_spec.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::UuidMetric do
+ it_behaves_like 'a correct instrumented metric value', { time_frame: 'none' }, Gitlab::CurrentSettings.uuid
+end
diff --git a/spec/lib/gitlab/usage/metrics/key_path_processor_spec.rb b/spec/lib/gitlab/usage/metrics/key_path_processor_spec.rb
new file mode 100644
index 00000000000..91c27825cce
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/key_path_processor_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::KeyPathProcessor do
+ describe '#unflatten_default_path' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:key_path, :value, :expected_hash) do
+ 'uuid' | nil | { uuid: nil }
+ 'uuid' | '1111' | { uuid: '1111' }
+ 'counts.issues' | nil | { counts: { issues: nil } }
+ 'counts.issues' | 100 | { counts: { issues: 100 } }
+ 'usage_activity_by_stage.verify.ci_builds' | 100 | { usage_activity_by_stage: { verify: { ci_builds: 100 } } }
+ end
+
+ with_them do
+ subject { described_class.process(key_path, value) }
+
+ it { is_expected.to eq(expected_hash) }
+ end
+ end
+end