diff options
-rw-r--r-- | app/services/wiki_pages/base_service.rb | 6 | ||||
-rw-r--r-- | changelogs/unreleased/wiki-usage-pings.yml | 5 | ||||
-rw-r--r-- | lib/gitlab/usage_data.rb | 17 | ||||
-rw-r--r-- | lib/gitlab/usage_data_counters/web_ide_counter.rb | 8 | ||||
-rw-r--r-- | lib/gitlab/usage_data_counters/wiki_page_counter.rb | 32 | ||||
-rw-r--r-- | spec/lib/gitlab/usage_data_counters/web_ide_counter_spec.rb | 20 | ||||
-rw-r--r-- | spec/lib/gitlab/usage_data_counters/wiki_page_counter_spec.rb | 69 | ||||
-rw-r--r-- | spec/lib/gitlab/usage_data_spec.rb | 40 | ||||
-rw-r--r-- | spec/services/wiki_pages/base_service_spec.rb | 27 | ||||
-rw-r--r-- | spec/services/wiki_pages/create_service_spec.rb | 25 | ||||
-rw-r--r-- | spec/services/wiki_pages/destroy_service_spec.rb | 12 | ||||
-rw-r--r-- | spec/services/wiki_pages/update_service_spec.rb | 25 |
12 files changed, 270 insertions, 16 deletions
diff --git a/app/services/wiki_pages/base_service.rb b/app/services/wiki_pages/base_service.rb index e259f5bd1bc..b9df690c2b7 100644 --- a/app/services/wiki_pages/base_service.rb +++ b/app/services/wiki_pages/base_service.rb @@ -8,6 +8,12 @@ module WikiPages page_data = Gitlab::DataBuilder::WikiPage.build(page, current_user, action) @project.execute_hooks(page_data, :wiki_page_hooks) @project.execute_services(page_data, :wiki_page_hooks) + increment_usage(action) + end + + # This method throws an error if the action is an unanticipated value. + def increment_usage(action) + Gitlab::UsageDataCounters::WikiPageCounter.count(action) end end end diff --git a/changelogs/unreleased/wiki-usage-pings.yml b/changelogs/unreleased/wiki-usage-pings.yml new file mode 100644 index 00000000000..c3d084228c3 --- /dev/null +++ b/changelogs/unreleased/wiki-usage-pings.yml @@ -0,0 +1,5 @@ +--- +title: Count wiki creation, update and delete events +merge_request: 30864 +author: +type: added diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb index 43072053e57..db1086c9cae 100644 --- a/lib/gitlab/usage_data.rb +++ b/lib/gitlab/usage_data.rb @@ -6,7 +6,9 @@ module Gitlab class << self def data(force_refresh: false) - Rails.cache.fetch('usage_data', force: force_refresh, expires_in: 2.weeks) { uncached_data } + Rails.cache.fetch('usage_data', force: force_refresh, expires_in: 2.weeks) do + uncached_data + end end def uncached_data @@ -128,12 +130,15 @@ module Gitlab } end + # @return [Hash<Symbol, Integer>] def usage_counters - { - web_ide_commits: Gitlab::UsageDataCounters::WebIdeCounter.total_commits_count, - web_ide_merge_requests: Gitlab::UsageDataCounters::WebIdeCounter.total_merge_requests_count, - web_ide_views: Gitlab::UsageDataCounters::WebIdeCounter.total_views_count - } + usage_data_counters.map(&:totals).reduce({}) { |a, b| a.merge(b) } + end + + # @return [Array<#totals>] An array of objects that respond to `#totals` + def usage_data_counters + [Gitlab::UsageDataCounters::WikiPageCounter, + Gitlab::UsageDataCounters::WebIdeCounter] end def components_usage_data diff --git a/lib/gitlab/usage_data_counters/web_ide_counter.rb b/lib/gitlab/usage_data_counters/web_ide_counter.rb index 899ad0db9c0..0718c1dd761 100644 --- a/lib/gitlab/usage_data_counters/web_ide_counter.rb +++ b/lib/gitlab/usage_data_counters/web_ide_counter.rb @@ -33,6 +33,14 @@ module Gitlab def total_views_count total_count(VIEWS_COUNT_KEY) end + + def totals + { + web_ide_commits: total_commits_count, + web_ide_views: total_views_count, + web_ide_merge_requests: total_merge_requests_count + } + end end end end diff --git a/lib/gitlab/usage_data_counters/wiki_page_counter.rb b/lib/gitlab/usage_data_counters/wiki_page_counter.rb new file mode 100644 index 00000000000..c8b59a3160c --- /dev/null +++ b/lib/gitlab/usage_data_counters/wiki_page_counter.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Gitlab::UsageDataCounters + class WikiPageCounter + extend RedisCounter + + KNOWN_EVENTS = %w[create update delete].map(&:freeze).freeze + + UnknownEvent = Class.new(StandardError) + + class << self + # Each event gets a unique Redis key + def redis_key(event) + raise UnknownEvent, event unless KNOWN_EVENTS.include?(event.to_s) + + "USAGE_WIKI_PAGES_#{event}".upcase + end + + def count(event) + increment(redis_key event) + end + + def read(event) + total_count(redis_key event) + end + + def totals + KNOWN_EVENTS.map { |e| ["wiki_pages_#{e}".to_sym, read(e)] }.to_h + end + end + end +end diff --git a/spec/lib/gitlab/usage_data_counters/web_ide_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/web_ide_counter_spec.rb index b5e32d1875f..7a01f7d1de8 100644 --- a/spec/lib/gitlab/usage_data_counters/web_ide_counter_spec.rb +++ b/spec/lib/gitlab/usage_data_counters/web_ide_counter_spec.rb @@ -33,4 +33,24 @@ describe Gitlab::UsageDataCounters::WebIdeCounter, :clean_gitlab_redis_shared_st it_behaves_like 'counter examples' end + + describe '.totals' do + commits = 5 + merge_requests = 3 + views = 2 + + before do + commits.times { described_class.increment_commits_count } + merge_requests.times { described_class.increment_merge_requests_count } + views.times { described_class.increment_views_count } + end + + it 'can report all totals' do + expect(described_class.totals).to include( + web_ide_commits: commits, + web_ide_views: views, + web_ide_merge_requests: merge_requests + ) + end + end end diff --git a/spec/lib/gitlab/usage_data_counters/wiki_page_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/wiki_page_counter_spec.rb new file mode 100644 index 00000000000..41afbbb191c --- /dev/null +++ b/spec/lib/gitlab/usage_data_counters/wiki_page_counter_spec.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::UsageDataCounters::WikiPageCounter, :clean_gitlab_redis_shared_state do + shared_examples :wiki_page_event do |event| + describe ".count(#{event})" do + it "increments the wiki page #{event} counter by 1" do + expect do + described_class.count(event) + end.to change { described_class.read(event) }.by 1 + end + end + + describe ".read(#{event})" do + event_count = 5 + + it "returns the total number of #{event} events" do + event_count.times do + described_class.count(event) + end + + expect(described_class.read(event)).to eq(event_count) + end + end + end + + include_examples :wiki_page_event, :create + include_examples :wiki_page_event, :update + include_examples :wiki_page_event, :delete + + describe 'totals' do + creations = 5 + edits = 3 + deletions = 2 + + before do + creations.times do + described_class.count(:create) + end + edits.times do + described_class.count(:update) + end + deletions.times do + described_class.count(:delete) + end + end + + it 'can report all totals' do + expect(described_class.totals).to include( + wiki_pages_update: edits, + wiki_pages_create: creations, + wiki_pages_delete: deletions + ) + end + end + + describe 'unknown events' do + error = described_class::UnknownEvent + + it 'cannot increment' do + expect { described_class.count(:wibble) }.to raise_error error + end + + it 'cannot read' do + expect { described_class.read(:wibble) }.to raise_error error + end + end +end diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index 270dd652c20..2289d906944 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -57,20 +57,18 @@ describe Gitlab::UsageData do gitaly database avg_cycle_analytics - web_ide_views - web_ide_commits - web_ide_merge_requests influxdb_metrics_enabled prometheus_metrics_enabled )) - end - - it 'calls expected usage data methods' do - expect(Gitlab::UsageDataCounters::WebIdeCounter).to receive(:total_commits_count) - expect(Gitlab::UsageDataCounters::WebIdeCounter).to receive(:total_merge_requests_count) - expect(Gitlab::UsageDataCounters::WebIdeCounter).to receive(:total_views_count) - subject + expect(subject).to include( + wiki_pages_create: a_kind_of(Integer), + wiki_pages_update: a_kind_of(Integer), + wiki_pages_delete: a_kind_of(Integer), + web_ide_views: a_kind_of(Integer), + web_ide_commits: a_kind_of(Integer), + web_ide_merge_requests: a_kind_of(Integer) + ) end it "gathers usage counts" do @@ -192,6 +190,28 @@ describe Gitlab::UsageData do end end + describe '#usage_data_counters' do + subject { described_class.usage_data_counters } + + it { is_expected.to all(respond_to :totals) } + + describe 'the results of calling #totals on all objects in the array' do + subject { described_class.usage_data_counters.map(&:totals) } + + it do + is_expected + .to all(be_a Hash) + .and all(have_attributes(keys: all(be_a Symbol), values: all(be_a Integer))) + end + end + + it 'does not have any conflicts' do + all_keys = subject.flat_map { |counter| counter.totals.keys } + + expect(all_keys.size).to eq all_keys.to_set.size + end + end + describe '#features_usage_data_ce' do subject { described_class.features_usage_data_ce } diff --git a/spec/services/wiki_pages/base_service_spec.rb b/spec/services/wiki_pages/base_service_spec.rb new file mode 100644 index 00000000000..2e70246c6f2 --- /dev/null +++ b/spec/services/wiki_pages/base_service_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe WikiPages::BaseService do + let(:project) { double('project') } + let(:user) { double('user') } + + subject(:service) { described_class.new(project, user, {}) } + + describe '#increment_usage' do + counter = Gitlab::UsageDataCounters::WikiPageCounter + error = counter::UnknownEvent + + it 'raises an error on unknown events' do + expect { subject.send(:increment_usage, :bad_event) }.to raise_error error + end + + context 'the event is valid' do + counter::KNOWN_EVENTS.each do |e| + it "updates the #{e} counter" do + expect { subject.send(:increment_usage, e) }.to change { counter.read(e) } + end + end + end + end +end diff --git a/spec/services/wiki_pages/create_service_spec.rb b/spec/services/wiki_pages/create_service_spec.rb index 84510dcf700..ef03a2e9788 100644 --- a/spec/services/wiki_pages/create_service_spec.rb +++ b/spec/services/wiki_pages/create_service_spec.rb @@ -14,6 +14,10 @@ describe WikiPages::CreateService do } end + let(:bad_opts) do + { title: '' } + end + subject(:service) { described_class.new(project, user, opts) } before do @@ -36,5 +40,26 @@ describe WikiPages::CreateService do service.execute end + + it 'counts wiki page creation' do + counter = Gitlab::UsageDataCounters::WikiPageCounter + + expect { service.execute }.to change { counter.read(:create) }.by 1 + end + + context 'when the options are bad' do + subject(:service) { described_class.new(project, user, bad_opts) } + + it 'does not count a creation event' do + counter = Gitlab::UsageDataCounters::WikiPageCounter + + expect { service.execute }.not_to change { counter.read(:create) } + end + + it 'reports the error' do + expect(service.execute).to be_invalid + .and have_attributes(errors: be_present) + end + end end end diff --git a/spec/services/wiki_pages/destroy_service_spec.rb b/spec/services/wiki_pages/destroy_service_spec.rb index c74eac4dad6..350a7eb123b 100644 --- a/spec/services/wiki_pages/destroy_service_spec.rb +++ b/spec/services/wiki_pages/destroy_service_spec.rb @@ -20,5 +20,17 @@ describe WikiPages::DestroyService do service.execute(page) end + + it 'increments the delete count' do + counter = Gitlab::UsageDataCounters::WikiPageCounter + + expect { service.execute(page) }.to change { counter.read(:delete) }.by 1 + end + + it 'does not increment the delete count if the deletion failed' do + counter = Gitlab::UsageDataCounters::WikiPageCounter + + expect { service.execute(nil) }.not_to change { counter.read(:delete) } + end end end diff --git a/spec/services/wiki_pages/update_service_spec.rb b/spec/services/wiki_pages/update_service_spec.rb index 19866bd3bfc..d5f46e7b2db 100644 --- a/spec/services/wiki_pages/update_service_spec.rb +++ b/spec/services/wiki_pages/update_service_spec.rb @@ -16,6 +16,10 @@ describe WikiPages::UpdateService do } end + let(:bad_opts) do + { title: '' } + end + subject(:service) { described_class.new(project, user, opts) } before do @@ -39,5 +43,26 @@ describe WikiPages::UpdateService do service.execute(page) end + + it 'counts edit events' do + counter = Gitlab::UsageDataCounters::WikiPageCounter + + expect { service.execute page }.to change { counter.read(:update) }.by 1 + end + + context 'when the options are bad' do + subject(:service) { described_class.new(project, user, bad_opts) } + + it 'does not count an edit event' do + counter = Gitlab::UsageDataCounters::WikiPageCounter + + expect { service.execute page }.not_to change { counter.read(:update) } + end + + it 'reports the error' do + expect(service.execute page).to be_invalid + .and have_attributes(errors: be_present) + end + end end end |