summaryrefslogtreecommitdiff
path: root/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb')
-rw-r--r--spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb277
1 files changed, 210 insertions, 67 deletions
diff --git a/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb
index 2ab349a67d9..f881da71251 100644
--- a/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb
@@ -8,25 +8,6 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
let(:entity3) { '34rfjuuy-ce56-sa35-ds34-dfer567dfrf2' }
let(:entity4) { '8b9a2671-2abf-4bec-a682-22f6a8f7bf31' }
- let(:weekly_event) { 'g_analytics_contribution' }
- let(:daily_event) { 'g_search' }
- let(:different_aggregation) { 'different_aggregation' }
-
- let(:known_events) do
- [
- { name: "g_analytics_contribution", redis_slot: "analytics", category: "analytics", expiry: 84, aggregation: "weekly" },
- { name: "g_analytics_valuestream", redis_slot: "analytics", category: "analytics", expiry: 84, aggregation: "daily" },
- { name: "g_analytics_productivity", redis_slot: "analytics", category: "productivity", expiry: 84, aggregation: "weekly" },
- { name: "g_compliance_dashboard", redis_slot: "compliance", category: "compliance", aggregation: "weekly" },
- { name: "g_search", category: "global", aggregation: "daily" },
- { name: "different_aggregation", category: "global", aggregation: "monthly" }
- ].map(&:with_indifferent_access)
- end
-
- before do
- allow(described_class).to receive(:known_events).and_return(known_events)
- end
-
around do |example|
# We need to freeze to a reference time
# because visits are grouped by the week number in the year
@@ -37,77 +18,239 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
Timecop.freeze(reference_time) { example.run }
end
- describe '.track_event' do
- it "raise error if metrics don't have same aggregation" do
- expect { described_class.track_event(entity1, different_aggregation, Date.current) } .to raise_error(Gitlab::UsageDataCounters::HLLRedisCounter::UnknownAggregation)
+ describe '.categories' do
+ it 'gets all unique category names' do
+ expect(described_class.categories).to contain_exactly('analytics', 'compliance', 'ide_edit', 'search', 'source_code', 'incident_management', 'issues_edit')
end
+ end
+
+ describe 'known_events' do
+ let(:weekly_event) { 'g_analytics_contribution' }
+ let(:daily_event) { 'g_analytics_search' }
+ let(:analytics_slot_event) { 'g_analytics_contribution' }
+ let(:compliance_slot_event) { 'g_compliance_dashboard' }
+ let(:category_analytics_event) { 'g_analytics_search' }
+ let(:category_productivity_event) { 'g_analytics_productivity' }
+ let(:no_slot) { 'no_slot' }
+ let(:different_aggregation) { 'different_aggregation' }
+ let(:custom_daily_event) { 'g_analytics_custom' }
- it 'raise error if metrics of unknown aggregation' do
- expect { described_class.track_event(entity1, 'unknown', Date.current) } .to raise_error(Gitlab::UsageDataCounters::HLLRedisCounter::UnknownEvent)
+ let(:global_category) { 'global' }
+ let(:compliance_category) {'compliance' }
+ let(:productivity_category) {'productivity' }
+ let(:analytics_category) { 'analytics' }
+
+ let(:known_events) do
+ [
+ { name: weekly_event, redis_slot: "analytics", category: analytics_category, expiry: 84, aggregation: "weekly" },
+ { name: daily_event, redis_slot: "analytics", category: analytics_category, expiry: 84, aggregation: "daily" },
+ { name: category_productivity_event, redis_slot: "analytics", category: productivity_category, aggregation: "weekly" },
+ { name: compliance_slot_event, redis_slot: "compliance", category: compliance_category, aggregation: "weekly" },
+ { name: no_slot, category: global_category, aggregation: "daily" },
+ { name: different_aggregation, category: global_category, aggregation: "monthly" }
+ ].map(&:with_indifferent_access)
end
- end
- describe '.unique_events' do
before do
- # events in current week, should not be counted as week is not complete
- described_class.track_event(entity1, weekly_event, Date.current)
- described_class.track_event(entity2, weekly_event, Date.current)
+ allow(described_class).to receive(:known_events).and_return(known_events)
+ end
- # Events last week
- described_class.track_event(entity1, weekly_event, 2.days.ago)
- described_class.track_event(entity1, weekly_event, 2.days.ago)
+ describe '.events_for_category' do
+ it 'gets the event names for given category' do
+ expect(described_class.events_for_category(:analytics)).to contain_exactly(weekly_event, daily_event)
+ end
+ end
- # Events 2 weeks ago
- described_class.track_event(entity1, weekly_event, 2.weeks.ago)
+ describe '.track_event' do
+ context 'when usage_ping is disabled' do
+ it 'does not track the event' do
+ stub_application_setting(usage_ping_enabled: false)
- # Events 4 weeks ago
- described_class.track_event(entity3, weekly_event, 4.weeks.ago)
- described_class.track_event(entity4, weekly_event, 29.days.ago)
+ described_class.track_event(entity1, weekly_event, Date.current)
- # events in current day should be counted in daily aggregation
- described_class.track_event(entity1, daily_event, Date.current)
- described_class.track_event(entity2, daily_event, Date.current)
+ expect(Gitlab::Redis::HLL).not_to receive(:add)
+ end
+ end
- # Events last week
- described_class.track_event(entity1, daily_event, 2.days.ago)
- described_class.track_event(entity1, daily_event, 2.days.ago)
+ context 'when usage_ping is enabled' do
+ before do
+ stub_application_setting(usage_ping_enabled: true)
+ end
- # Events 2 weeks ago
- described_class.track_event(entity1, daily_event, 14.days.ago)
+ it "raise error if metrics don't have same aggregation" do
+ expect { described_class.track_event(entity1, different_aggregation, Date.current) } .to raise_error(Gitlab::UsageDataCounters::HLLRedisCounter::UnknownAggregation)
+ end
- # Events 4 weeks ago
- described_class.track_event(entity3, daily_event, 28.days.ago)
- described_class.track_event(entity4, daily_event, 29.days.ago)
- end
+ it 'raise error if metrics of unknown aggregation' do
+ expect { described_class.track_event(entity1, 'unknown', Date.current) } .to raise_error(Gitlab::UsageDataCounters::HLLRedisCounter::UnknownEvent)
+ end
- it 'raise error if metrics are not in the same slot' do
- expect { described_class.unique_events(event_names: %w(g_analytics_contribution g_compliance_dashboard), start_date: 4.weeks.ago, end_date: Date.current) }.to raise_error('Events should be in same slot')
- end
+ context 'for weekly events' do
+ it 'sets the keys in Redis to expire automatically after the given expiry time' do
+ described_class.track_event(entity1, "g_analytics_contribution")
- it 'raise error if metrics are not in the same category' do
- expect { described_class.unique_events(event_names: %w(g_analytics_contribution g_analytics_productivity), start_date: 4.weeks.ago, end_date: Date.current) }.to raise_error('Events should be in same category')
- end
+ Gitlab::Redis::SharedState.with do |redis|
+ keys = redis.scan_each(match: "g_{analytics}_contribution-*").to_a
+ expect(keys).not_to be_empty
+
+ keys.each do |key|
+ expect(redis.ttl(key)).to be_within(5.seconds).of(12.weeks)
+ end
+ end
+ end
+
+ it 'sets the keys in Redis to expire automatically after 6 weeks by default' do
+ described_class.track_event(entity1, "g_compliance_dashboard")
+
+ Gitlab::Redis::SharedState.with do |redis|
+ keys = redis.scan_each(match: "g_{compliance}_dashboard-*").to_a
+ expect(keys).not_to be_empty
+
+ keys.each do |key|
+ expect(redis.ttl(key)).to be_within(5.seconds).of(6.weeks)
+ end
+ end
+ end
+ end
+
+ context 'for daily events' do
+ it 'sets the keys in Redis to expire after the given expiry time' do
+ described_class.track_event(entity1, "g_analytics_search")
+
+ Gitlab::Redis::SharedState.with do |redis|
+ keys = redis.scan_each(match: "*-g_{analytics}_search").to_a
+ expect(keys).not_to be_empty
+
+ keys.each do |key|
+ expect(redis.ttl(key)).to be_within(5.seconds).of(84.days)
+ end
+ end
+ end
+
+ it 'sets the keys in Redis to expire after 29 days by default' do
+ described_class.track_event(entity1, "no_slot")
- it "raise error if metrics don't have same aggregation" do
- expect { described_class.unique_events(event_names: %w(g_analytics_contribution g_analytics_valuestream), start_date: 4.weeks.ago, end_date: Date.current) }.to raise_error('Events should have same aggregation level')
+ Gitlab::Redis::SharedState.with do |redis|
+ keys = redis.scan_each(match: "*-{no_slot}").to_a
+ expect(keys).not_to be_empty
+
+ keys.each do |key|
+ expect(redis.ttl(key)).to be_within(5.seconds).of(29.days)
+ end
+ end
+ end
+ end
+ end
end
- context 'when data for the last complete week' do
- it { expect(described_class.unique_events(event_names: weekly_event, start_date: 1.week.ago, end_date: Date.current)).to eq(1) }
+ describe '.unique_events' do
+ before do
+ # events in current week, should not be counted as week is not complete
+ described_class.track_event(entity1, weekly_event, Date.current)
+ described_class.track_event(entity2, weekly_event, Date.current)
+
+ # Events last week
+ described_class.track_event(entity1, weekly_event, 2.days.ago)
+ described_class.track_event(entity1, weekly_event, 2.days.ago)
+ described_class.track_event(entity1, no_slot, 2.days.ago)
+
+ # Events 2 weeks ago
+ described_class.track_event(entity1, weekly_event, 2.weeks.ago)
+
+ # Events 4 weeks ago
+ described_class.track_event(entity3, weekly_event, 4.weeks.ago)
+ described_class.track_event(entity4, weekly_event, 29.days.ago)
+
+ # events in current day should be counted in daily aggregation
+ described_class.track_event(entity1, daily_event, Date.current)
+ described_class.track_event(entity2, daily_event, Date.current)
+
+ # Events last week
+ described_class.track_event(entity1, daily_event, 2.days.ago)
+ described_class.track_event(entity1, daily_event, 2.days.ago)
+
+ # Events 2 weeks ago
+ described_class.track_event(entity1, daily_event, 14.days.ago)
+
+ # Events 4 weeks ago
+ described_class.track_event(entity3, daily_event, 28.days.ago)
+ described_class.track_event(entity4, daily_event, 29.days.ago)
+ end
+
+ it 'raise error if metrics are not in the same slot' do
+ expect { described_class.unique_events(event_names: [compliance_slot_event, analytics_slot_event], start_date: 4.weeks.ago, end_date: Date.current) }.to raise_error('Events should be in same slot')
+ end
+
+ it 'raise error if metrics are not in the same category' do
+ expect { described_class.unique_events(event_names: [category_analytics_event, category_productivity_event], start_date: 4.weeks.ago, end_date: Date.current) }.to raise_error('Events should be in same category')
+ end
+
+ it "raise error if metrics don't have same aggregation" do
+ expect { described_class.unique_events(event_names: [daily_event, weekly_event], start_date: 4.weeks.ago, end_date: Date.current) }.to raise_error('Events should have same aggregation level')
+ end
+
+ context 'when data for the last complete week' do
+ it { expect(described_class.unique_events(event_names: weekly_event, start_date: 1.week.ago, end_date: Date.current)).to eq(1) }
+ end
+
+ context 'when data for the last 4 complete weeks' do
+ it { expect(described_class.unique_events(event_names: weekly_event, start_date: 4.weeks.ago, end_date: Date.current)).to eq(2) }
+ end
+
+ context 'when data for the week 4 weeks ago' do
+ it { expect(described_class.unique_events(event_names: weekly_event, start_date: 4.weeks.ago, end_date: 3.weeks.ago)).to eq(1) }
+ end
+
+ context 'when using daily aggregation' do
+ it { expect(described_class.unique_events(event_names: daily_event, start_date: 7.days.ago, end_date: Date.current)).to eq(2) }
+ it { expect(described_class.unique_events(event_names: daily_event, start_date: 28.days.ago, end_date: Date.current)).to eq(3) }
+ it { expect(described_class.unique_events(event_names: daily_event, start_date: 28.days.ago, end_date: 21.days.ago)).to eq(1) }
+ end
+
+ context 'when no slot is set' do
+ it { expect(described_class.unique_events(event_names: no_slot, start_date: 7.days.ago, end_date: Date.current)).to eq(1) }
+ end
end
+ end
- context 'when data for the last 4 complete weeks' do
- it { expect(described_class.unique_events(event_names: weekly_event, start_date: 4.weeks.ago, end_date: Date.current)).to eq(2) }
+ describe 'unique_events_data' do
+ let(:known_events) do
+ [
+ { name: 'event1_slot', redis_slot: "slot", category: 'category1', aggregation: "weekly" },
+ { name: 'event2_slot', redis_slot: "slot", category: 'category1', aggregation: "weekly" },
+ { name: 'event3', category: 'category2', aggregation: "weekly" },
+ { name: 'event4', category: 'category2', aggregation: "weekly" }
+ ].map(&:with_indifferent_access)
end
- context 'when data for the week 4 weeks ago' do
- it { expect(described_class.unique_events(event_names: weekly_event, start_date: 4.weeks.ago, end_date: 3.weeks.ago)).to eq(1) }
+ before do
+ allow(described_class).to receive(:known_events).and_return(known_events)
+ allow(described_class).to receive(:categories).and_return(%w(category1 category2))
+
+ described_class.track_event(entity1, 'event1_slot', 2.days.ago)
+ described_class.track_event(entity2, 'event2_slot', 2.days.ago)
+ described_class.track_event(entity3, 'event2_slot', 2.weeks.ago)
+
+ # events in different slots
+ described_class.track_event(entity2, 'event3', 2.days.ago)
+ described_class.track_event(entity2, 'event4', 2.days.ago)
end
- context 'when using daily aggregation' do
- it { expect(described_class.unique_events(event_names: daily_event, start_date: 7.days.ago, end_date: Date.current)).to eq(2) }
- it { expect(described_class.unique_events(event_names: daily_event, start_date: 28.days.ago, end_date: Date.current)).to eq(3) }
- it { expect(described_class.unique_events(event_names: daily_event, start_date: 28.days.ago, end_date: 21.days.ago)).to eq(1) }
+ it 'returns the number of unique events for all known events' do
+ results = {
+ 'category1' => {
+ 'event1_slot' => 1,
+ 'event2_slot' => 1,
+ 'category1_total_unique_counts_weekly' => 2,
+ 'category1_total_unique_counts_monthly' => 3
+ },
+ 'category2' => {
+ 'event3' => 1,
+ 'event4' => 1
+ }
+ }
+
+ expect(subject.unique_events_data).to eq(results)
end
end
end