Commit ba52b59f authored by Mayra Cabrera's avatar Mayra Cabrera

Merge branch '229918-track-health-status-usage-ping' into 'master'

Track issue health status changes in usage ping

See merge request gitlab-org/gitlab!44417
parents de14944a 0d02d9c7
......@@ -15,6 +15,8 @@ module EE
health_status = noteable.health_status&.humanize(capitalize: false)
body = health_status ? "changed health status to **#{health_status}**" : 'removed the health status'
issue_activity_counter.track_issue_health_status_changed_action(author: author) if noteable.is_a?(Issue)
create_note(NoteSummary.new(noteable, project, author, body, action: 'health_status'))
end
......
---
title: Track issue health status changes in usage ping
merge_request: 44417
author:
type: other
# frozen_string_literal: true
module EE
module Gitlab
module UsageDataCounters
module IssueActivityUniqueCounter
extend ActiveSupport::Concern
ISSUE_HEALTH_STATUS_CHANGED = 'g_project_management_issue_health_status_changed'
class_methods do
def track_issue_health_status_changed_action(author:, time: Time.zone.now)
track_unique_action(ISSUE_HEALTH_STATUS_CHANGED, author, time)
end
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::UsageDataCounters::IssueActivityUniqueCounter, :clean_gitlab_redis_shared_state do
let(:user1) { build(:user, id: 1) }
let(:user2) { build(:user, id: 2) }
let(:user3) { build(:user, id: 3) }
let(:time) { Time.zone.now }
context 'for Issue health status changed actions' do
it_behaves_like 'a tracked issue edit event' do
let(:action) { described_class::ISSUE_HEALTH_STATUS_CHANGED }
def track_action(params)
described_class.track_issue_health_status_changed_action(**params)
end
end
end
end
......@@ -14,11 +14,11 @@ RSpec.describe ::SystemNotes::IssuablesService do
let(:service) { described_class.new(noteable: noteable, project: project, author: author) }
describe '#change_health_status_note' do
subject { service.change_health_status_note }
context 'when health_status changed' do
let(:noteable) { create(:issue, project: project, title: 'Lorem ipsum', health_status: 'at_risk') }
subject { service.change_health_status_note }
it_behaves_like 'a system note' do
let(:action) { 'health_status' }
end
......@@ -31,8 +31,6 @@ RSpec.describe ::SystemNotes::IssuablesService do
context 'when health_status removed' do
let(:noteable) { create(:issue, project: project, title: 'Lorem ipsum', health_status: nil) }
subject { service.change_health_status_note }
it_behaves_like 'a system note' do
let(:action) { 'health_status' }
end
......@@ -41,6 +39,12 @@ RSpec.describe ::SystemNotes::IssuablesService do
expect(subject.note).to eq 'removed the health status'
end
end
it 'tracks the issue event in usage ping' do
expect(Gitlab::UsageDataCounters::IssueActivityUniqueCounter).to receive(:track_issue_health_status_changed_action).with(author: author)
subject
end
end
describe '#publish_issue_to_status_page' do
......
......@@ -174,3 +174,5 @@ module Gitlab
end
end
end
Gitlab::UsageDataCounters::IssueActivityUniqueCounter.prepend_if_ee('EE::Gitlab::UsageDataCounters::IssueActivityUniqueCounter')
......@@ -315,3 +315,7 @@
category: issues_edit
redis_slot: project_management
aggregation: daily
- name: g_project_management_issue_health_status_changed
category: issues_edit
redis_slot: project_management
aggregation: daily
......@@ -88,7 +88,7 @@ RSpec.describe Gitlab::ExclusiveLeaseHelpers, :clean_gitlab_redis_shared_state d
let(:options) { { retries: 0 } }
it 'never sleeps' do
expect(class_instance).not_to receive(:sleep)
expect_any_instance_of(Gitlab::ExclusiveLeaseHelpers::SleepingLock).not_to receive(:sleep)
expect { subject }.to raise_error('Failed to obtain a lock')
end
......@@ -98,7 +98,7 @@ RSpec.describe Gitlab::ExclusiveLeaseHelpers, :clean_gitlab_redis_shared_state d
let(:options) { { retries: 1, sleep_sec: 0.05.seconds } }
it 'receives the specified argument' do
expect_any_instance_of(Object).to receive(:sleep).with(0.05.seconds).once
expect_any_instance_of(Gitlab::ExclusiveLeaseHelpers::SleepingLock).to receive(:sleep).with(0.05.seconds).once
expect { subject }.to raise_error('Failed to obtain a lock')
end
......@@ -108,8 +108,8 @@ RSpec.describe Gitlab::ExclusiveLeaseHelpers, :clean_gitlab_redis_shared_state d
let(:options) { { retries: 2, sleep_sec: ->(num) { 0.1 + num } } }
it 'receives the specified argument' do
expect_any_instance_of(Object).to receive(:sleep).with(1.1.seconds).once
expect_any_instance_of(Object).to receive(:sleep).with(2.1.seconds).once
expect_any_instance_of(Gitlab::ExclusiveLeaseHelpers::SleepingLock).to receive(:sleep).with(1.1.seconds).once
expect_any_instance_of(Gitlab::ExclusiveLeaseHelpers::SleepingLock).to receive(:sleep).with(2.1.seconds).once
expect { subject }.to raise_error('Failed to obtain a lock')
end
......
......@@ -59,7 +59,7 @@ RSpec.describe Gitlab::ImportExport::AttributesFinder do
end
before do
allow_any_instance_of(Gitlab::ImportExport).to receive(:config_file).and_return(test_config)
allow(Gitlab::ImportExport).to receive(:config_file).and_return(test_config)
end
it 'generates hash from project tree config' do
......
......@@ -12,7 +12,7 @@ RSpec.describe Gitlab::ImportExport::Group::LegacyTreeSaver do
before do
group.add_maintainer(user)
allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
allow(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
end
after do
......
......@@ -12,7 +12,7 @@ RSpec.describe Gitlab::ImportExport::Importer do
subject(:importer) { described_class.new(project) }
before do
allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(test_path)
allow(Gitlab::ImportExport).to receive(:storage_path).and_return(test_path)
allow_any_instance_of(Gitlab::ImportExport::FileImporter).to receive(:remove_import_file)
stub_uploads_object_storage(FileUploader)
......
......@@ -13,7 +13,7 @@ RSpec.describe Gitlab::ImportExport::LfsRestorer do
subject(:restorer) { described_class.new(project: project, shared: shared) }
before do
allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
allow(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
FileUtils.mkdir_p(shared.export_path)
end
......
......@@ -26,7 +26,7 @@ RSpec.describe API::ProjectExport, :clean_gitlab_redis_cache do
let(:export_path) { "#{Dir.tmpdir}/project_export_spec" }
before do
allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
allow(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
allow_next_instance_of(ProjectExportWorker) do |job|
allow(job).to receive(:jid).and_return(SecureRandom.hex(8))
end
......
......@@ -15,7 +15,7 @@ module ImportExport
export_path = [prefix, 'spec', 'fixtures', 'lib', 'gitlab', 'import_export', name].compact
export_path = File.join(*export_path)
allow_any_instance_of(Gitlab::ImportExport).to receive(:export_path) { export_path }
allow(Gitlab::ImportExport).to receive(:export_path) { export_path }
end
def setup_reader(reader)
......
# frozen_string_literal: true
# This patch allows stubbing of prepended methods
# Based on https://github.com/rspec/rspec-mocks/pull/1218
module RSpec
module Mocks
module InstanceMethodStasherForPrependedMethods
private
def method_owned_by_klass?
owner = @klass.instance_method(@method).owner
owner = owner.class unless Module === owner
owner == @klass ||
# When `extend self` is used, and not under any instance of
(owner.singleton_class == @klass && !Mocks.space.any_instance_recorder_for(owner, true)) ||
!method_defined_on_klass?(owner)
end
end
end
end
module RSpec
module Mocks
module MethodDoubleForPrependedMethods
def restore_original_method
return show_frozen_warning if object_singleton_class.frozen?
return unless @method_is_proxied
remove_method_from_definition_target
if @method_stasher.method_is_stashed?
@method_stasher.restore
restore_original_visibility
end
@method_is_proxied = false
end
def restore_original_visibility
method_owner.__send__(@original_visibility, @method_name)
end
private
def method_owner
@method_owner ||= Object.instance_method(:method).bind(object).call(@method_name).owner
end
end
end
end
RSpec::Mocks::InstanceMethodStasher.prepend(RSpec::Mocks::InstanceMethodStasherForPrependedMethods)
RSpec::Mocks::MethodDouble.prepend(RSpec::Mocks::MethodDoubleForPrependedMethods)
# frozen_string_literal: true
RSpec.shared_examples 'a tracked issue edit event' do |event|
before do
stub_application_setting(usage_ping_enabled: true)
end
def count_unique(date_from:, date_to:)
Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names: action, start_date: date_from, end_date: date_to)
end
specify do
aggregate_failures do
expect(track_action(author: user1)).to be_truthy
expect(track_action(author: user1)).to be_truthy
expect(track_action(author: user2)).to be_truthy
expect(track_action(author: user3, time: time - 3.days)).to be_truthy
expect(count_unique(date_from: time, date_to: time)).to eq(2)
expect(count_unique(date_from: time - 5.days, date_to: 1.day.since(time))).to eq(3)
end
end
it 'does not track edit actions if author is not present' do
expect(track_action(author: nil)).to be_nil
end
context 'when feature flag track_issue_activity_actions is disabled' do
it 'does not track edit actions' do
stub_feature_flags(track_issue_activity_actions: false)
expect(track_action(author: user1)).to be_nil
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment