summaryrefslogtreecommitdiff
path: root/spec/lib/gitlab/usage_data_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/lib/gitlab/usage_data_spec.rb')
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb344
1 files changed, 298 insertions, 46 deletions
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index a46778bb6c3..9c6aab10083 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -7,6 +7,8 @@ describe Gitlab::UsageData, :aggregate_failures do
before do
allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(false)
+
+ stub_object_store_settings
end
shared_examples "usage data execution" do
@@ -42,6 +44,9 @@ describe Gitlab::UsageData, :aggregate_failures do
expect(count_data[:projects_jira_active]).to eq(4)
expect(count_data[:projects_jira_server_active]).to eq(2)
expect(count_data[:projects_jira_cloud_active]).to eq(2)
+ expect(count_data[:jira_imports_projects_count]).to eq(2)
+ expect(count_data[:jira_imports_total_imported_count]).to eq(3)
+ expect(count_data[:jira_imports_total_imported_issues_count]).to eq(13)
expect(count_data[:projects_slack_notifications_active]).to eq(2)
expect(count_data[:projects_slack_slash_active]).to eq(1)
expect(count_data[:projects_slack_active]).to eq(2)
@@ -57,6 +62,9 @@ describe Gitlab::UsageData, :aggregate_failures do
expect(count_data[:issues_using_zoom_quick_actions]).to eq(3)
expect(count_data[:issues_with_embedded_grafana_charts_approx]).to eq(2)
expect(count_data[:incident_issues]).to eq(4)
+ expect(count_data[:issues_created_gitlab_alerts]).to eq(1)
+ expect(count_data[:alert_bot_incident_issues]).to eq(4)
+ expect(count_data[:incident_labeled_issues]).to eq(3)
expect(count_data[:clusters_enabled]).to eq(6)
expect(count_data[:project_clusters_enabled]).to eq(4)
@@ -82,6 +90,56 @@ describe Gitlab::UsageData, :aggregate_failures do
expect(count_data[:clusters_management_project]).to eq(1)
end
+ it 'gathers object store usage correctly' do
+ expect(subject[:object_store]).to eq(
+ { artifacts: { enabled: true, object_store: { enabled: true, direct_upload: true, background_upload: false, provider: "AWS" } },
+ external_diffs: { enabled: false },
+ lfs: { enabled: true, object_store: { enabled: false, direct_upload: true, background_upload: false, provider: "AWS" } },
+ uploads: { enabled: nil, object_store: { enabled: false, direct_upload: true, background_upload: false, provider: "AWS" } },
+ packages: { enabled: true, object_store: { enabled: false, direct_upload: false, background_upload: true, provider: "AWS" } } }
+ )
+ end
+
+ context 'with existing container expiration policies' do
+ let_it_be(:disabled) { create(:container_expiration_policy, enabled: false) }
+ let_it_be(:enabled) { create(:container_expiration_policy, enabled: true) }
+
+ %i[keep_n cadence older_than].each do |attribute|
+ ContainerExpirationPolicy.send("#{attribute}_options").keys.each do |value|
+ let_it_be("container_expiration_policy_with_#{attribute}_set_to_#{value}") { create(:container_expiration_policy, attribute => value) }
+ end
+ end
+
+ let(:inactive_policies) { ::ContainerExpirationPolicy.where(enabled: false) }
+ let(:active_policies) { ::ContainerExpirationPolicy.active }
+
+ subject { described_class.data[:counts] }
+
+ it 'gathers usage data' do
+ expect(subject[:projects_with_expiration_policy_enabled]).to eq 20
+ expect(subject[:projects_with_expiration_policy_disabled]).to eq 1
+
+ expect(subject[:projects_with_expiration_policy_enabled_with_keep_n_unset]).to eq 14
+ expect(subject[:projects_with_expiration_policy_enabled_with_keep_n_set_to_1]).to eq 1
+ expect(subject[:projects_with_expiration_policy_enabled_with_keep_n_set_to_5]).to eq 1
+ expect(subject[:projects_with_expiration_policy_enabled_with_keep_n_set_to_10]).to eq 1
+ expect(subject[:projects_with_expiration_policy_enabled_with_keep_n_set_to_25]).to eq 1
+ expect(subject[:projects_with_expiration_policy_enabled_with_keep_n_set_to_50]).to eq 1
+
+ expect(subject[:projects_with_expiration_policy_enabled_with_older_than_unset]).to eq 16
+ expect(subject[:projects_with_expiration_policy_enabled_with_older_than_set_to_7d]).to eq 1
+ expect(subject[:projects_with_expiration_policy_enabled_with_older_than_set_to_14d]).to eq 1
+ expect(subject[:projects_with_expiration_policy_enabled_with_older_than_set_to_30d]).to eq 1
+ expect(subject[:projects_with_expiration_policy_enabled_with_older_than_set_to_90d]).to eq 1
+
+ expect(subject[:projects_with_expiration_policy_enabled_with_cadence_set_to_1d]).to eq 12
+ expect(subject[:projects_with_expiration_policy_enabled_with_cadence_set_to_7d]).to eq 5
+ expect(subject[:projects_with_expiration_policy_enabled_with_cadence_set_to_14d]).to eq 1
+ expect(subject[:projects_with_expiration_policy_enabled_with_cadence_set_to_1month]).to eq 1
+ expect(subject[:projects_with_expiration_policy_enabled_with_cadence_set_to_3month]).to eq 1
+ end
+ end
+
it 'works when queries time out' do
allow_any_instance_of(ActiveRecord::Relation)
.to receive(:count).and_raise(ActiveRecord::StatementInvalid.new(''))
@@ -101,6 +159,7 @@ describe Gitlab::UsageData, :aggregate_failures do
subject { described_class.usage_data_counters }
it { is_expected.to all(respond_to :totals) }
+ it { is_expected.to all(respond_to :fallback_totals) }
describe 'the results of calling #totals on all objects in the array' do
subject { described_class.usage_data_counters.map(&:totals) }
@@ -109,6 +168,13 @@ describe Gitlab::UsageData, :aggregate_failures do
it { is_expected.to all(have_attributes(keys: all(be_a Symbol), values: all(be_a Integer))) }
end
+ describe 'the results of calling #fallback_totals on all objects in the array' do
+ subject { described_class.usage_data_counters.map(&:fallback_totals) }
+
+ it { is_expected.to all(be_a Hash) }
+ it { is_expected.to all(have_attributes(keys: all(be_a Symbol), values: all(eq(-1)))) }
+ end
+
it 'does not have any conflicts' do
all_keys = subject.flat_map { |counter| counter.totals.keys }
@@ -128,6 +194,14 @@ describe Gitlab::UsageData, :aggregate_failures do
end
end
+ describe '.recording_ce_finished_at' do
+ subject { described_class.recording_ce_finish_data }
+
+ it 'gathers time ce recording finishes at' do
+ expect(subject[:recording_ce_finished_at]).to be_a(Time)
+ end
+ end
+
context 'when not relying on database records' do
describe '#features_usage_data_ce' do
subject { described_class.features_usage_data_ce }
@@ -143,42 +217,20 @@ describe Gitlab::UsageData, :aggregate_failures do
expect(subject[:dependency_proxy_enabled]).to eq(Gitlab.config.dependency_proxy.enabled)
expect(subject[:gitlab_shared_runners_enabled]).to eq(Gitlab.config.gitlab_ci.shared_runners_enabled)
expect(subject[:web_ide_clientside_preview_enabled]).to eq(Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?)
+ expect(subject[:grafana_link_enabled]).to eq(Gitlab::CurrentSettings.grafana_enabled?)
end
- context 'with existing container expiration policies' do
- let_it_be(:disabled) { create(:container_expiration_policy, enabled: false) }
- let_it_be(:enabled) { create(:container_expiration_policy, enabled: true) }
- %i[keep_n cadence older_than].each do |attribute|
- ContainerExpirationPolicy.send("#{attribute}_options").keys.each do |value|
- let_it_be("container_expiration_policy_with_#{attribute}_set_to_#{value}") { create(:container_expiration_policy, attribute => value) }
- end
+ context 'with embedded grafana' do
+ it 'returns true when embedded grafana is enabled' do
+ stub_application_setting(grafana_enabled: true)
+
+ expect(subject[:grafana_link_enabled]).to eq(true)
end
- let(:inactive_policies) { ::ContainerExpirationPolicy.where(enabled: false) }
- let(:active_policies) { ::ContainerExpirationPolicy.active }
-
- it 'gathers usage data' do
- expect(subject[:projects_with_expiration_policy_enabled]).to eq 16
- expect(subject[:projects_with_expiration_policy_disabled]).to eq 1
-
- expect(subject[:projects_with_expiration_policy_enabled_with_keep_n_unset]).to eq 10
- expect(subject[:projects_with_expiration_policy_enabled_with_keep_n_set_to_1]).to eq 1
- expect(subject[:projects_with_expiration_policy_enabled_with_keep_n_set_to_5]).to eq 1
- expect(subject[:projects_with_expiration_policy_enabled_with_keep_n_set_to_10]).to eq 1
- expect(subject[:projects_with_expiration_policy_enabled_with_keep_n_set_to_25]).to eq 1
- expect(subject[:projects_with_expiration_policy_enabled_with_keep_n_set_to_50]).to eq 1
-
- expect(subject[:projects_with_expiration_policy_enabled_with_older_than_unset]).to eq 12
- expect(subject[:projects_with_expiration_policy_enabled_with_older_than_set_to_7d]).to eq 1
- expect(subject[:projects_with_expiration_policy_enabled_with_older_than_set_to_14d]).to eq 1
- expect(subject[:projects_with_expiration_policy_enabled_with_older_than_set_to_30d]).to eq 1
- expect(subject[:projects_with_expiration_policy_enabled_with_older_than_set_to_90d]).to eq 1
-
- expect(subject[:projects_with_expiration_policy_enabled_with_cadence_set_to_1d]).to eq 12
- expect(subject[:projects_with_expiration_policy_enabled_with_cadence_set_to_7d]).to eq 1
- expect(subject[:projects_with_expiration_policy_enabled_with_cadence_set_to_14d]).to eq 1
- expect(subject[:projects_with_expiration_policy_enabled_with_cadence_set_to_1month]).to eq 1
- expect(subject[:projects_with_expiration_policy_enabled_with_cadence_set_to_3month]).to eq 1
+ it 'returns false when embedded grafana is disabled' do
+ stub_application_setting(grafana_enabled: false)
+
+ expect(subject[:grafana_link_enabled]).to eq(false)
end
end
end
@@ -223,6 +275,66 @@ describe Gitlab::UsageData, :aggregate_failures do
end
end
+ describe '#object_store_config' do
+ let(:component) { 'lfs' }
+
+ subject { described_class.object_store_config(component) }
+
+ context 'when object_store is not configured' do
+ it 'returns component enable status only' do
+ allow(Settings).to receive(:[]).with(component).and_return({ 'enabled' => false })
+
+ expect(subject).to eq({ enabled: false })
+ end
+ end
+
+ context 'when object_store is configured' do
+ it 'returns filtered object store config' do
+ allow(Settings).to receive(:[]).with(component)
+ .and_return(
+ { 'enabled' => true,
+ 'object_store' =>
+ { 'enabled' => true,
+ 'remote_directory' => component,
+ 'direct_upload' => true,
+ 'connection' =>
+ { 'provider' => 'AWS', 'aws_access_key_id' => 'minio', 'aws_secret_access_key' => 'gdk-minio', 'region' => 'gdk', 'endpoint' => 'http://127.0.0.1:9000', 'path_style' => true },
+ 'background_upload' => false,
+ 'proxy_download' => false } })
+
+ expect(subject).to eq(
+ { enabled: true, object_store: { enabled: true, direct_upload: true, background_upload: false, provider: "AWS" } })
+ end
+ end
+
+ context 'when retrieve component setting meets exception' do
+ it 'returns -1 for component enable status' do
+ allow(Settings).to receive(:[]).with(component).and_raise(StandardError)
+
+ expect(subject).to eq({ enabled: -1 })
+ end
+ end
+ end
+
+ describe '#object_store_usage_data' do
+ subject { described_class.object_store_usage_data }
+
+ it 'fetches object store config of five components' do
+ %w(artifacts external_diffs lfs uploads packages).each do |component|
+ expect(described_class).to receive(:object_store_config).with(component).and_return("#{component}_object_store_config")
+ end
+
+ expect(subject).to eq(
+ object_store: {
+ artifacts: 'artifacts_object_store_config',
+ external_diffs: 'external_diffs_object_store_config',
+ lfs: 'lfs_object_store_config',
+ uploads: 'uploads_object_store_config',
+ packages: 'packages_object_store_config'
+ })
+ end
+ end
+
describe '#cycle_analytics_usage_data' do
subject { described_class.cycle_analytics_usage_data }
@@ -244,18 +356,132 @@ describe Gitlab::UsageData, :aggregate_failures do
describe '#ingress_modsecurity_usage' do
subject { described_class.ingress_modsecurity_usage }
- it 'gathers variable data' do
- allow_any_instance_of(
- ::Clusters::Applications::IngressModsecurityUsageService
- ).to receive(:execute).and_return(
- {
- ingress_modsecurity_blocking: 1,
- ingress_modsecurity_disabled: 2
- }
- )
-
- expect(subject[:ingress_modsecurity_blocking]).to eq(1)
- expect(subject[:ingress_modsecurity_disabled]).to eq(2)
+ let(:environment) { create(:environment) }
+ let(:project) { environment.project }
+ let(:environment_scope) { '*' }
+ let(:deployment) { create(:deployment, :success, environment: environment, project: project, cluster: cluster) }
+ let(:cluster) { create(:cluster, environment_scope: environment_scope, projects: [project]) }
+ let(:ingress_mode) { :modsecurity_blocking }
+ let!(:ingress) { create(:clusters_applications_ingress, ingress_mode, cluster: cluster) }
+
+ context 'when cluster is disabled' do
+ let(:cluster) { create(:cluster, :disabled, projects: [project]) }
+
+ it 'gathers ingress data' do
+ expect(subject[:ingress_modsecurity_logging]).to eq(0)
+ expect(subject[:ingress_modsecurity_blocking]).to eq(0)
+ expect(subject[:ingress_modsecurity_disabled]).to eq(0)
+ expect(subject[:ingress_modsecurity_not_installed]).to eq(0)
+ end
+ end
+
+ context 'when deployment is unsuccessful' do
+ let!(:deployment) { create(:deployment, :failed, environment: environment, project: project, cluster: cluster) }
+
+ it 'gathers ingress data' do
+ expect(subject[:ingress_modsecurity_logging]).to eq(0)
+ expect(subject[:ingress_modsecurity_blocking]).to eq(0)
+ expect(subject[:ingress_modsecurity_disabled]).to eq(0)
+ expect(subject[:ingress_modsecurity_not_installed]).to eq(0)
+ end
+ end
+
+ context 'when deployment is successful' do
+ let!(:deployment) { create(:deployment, :success, environment: environment, project: project, cluster: cluster) }
+
+ context 'when modsecurity is in blocking mode' do
+ it 'gathers ingress data' do
+ expect(subject[:ingress_modsecurity_logging]).to eq(0)
+ expect(subject[:ingress_modsecurity_blocking]).to eq(1)
+ expect(subject[:ingress_modsecurity_disabled]).to eq(0)
+ expect(subject[:ingress_modsecurity_not_installed]).to eq(0)
+ end
+ end
+
+ context 'when modsecurity is in logging mode' do
+ let(:ingress_mode) { :modsecurity_logging }
+
+ it 'gathers ingress data' do
+ expect(subject[:ingress_modsecurity_logging]).to eq(1)
+ expect(subject[:ingress_modsecurity_blocking]).to eq(0)
+ expect(subject[:ingress_modsecurity_disabled]).to eq(0)
+ expect(subject[:ingress_modsecurity_not_installed]).to eq(0)
+ end
+ end
+
+ context 'when modsecurity is disabled' do
+ let(:ingress_mode) { :modsecurity_disabled }
+
+ it 'gathers ingress data' do
+ expect(subject[:ingress_modsecurity_logging]).to eq(0)
+ expect(subject[:ingress_modsecurity_blocking]).to eq(0)
+ expect(subject[:ingress_modsecurity_disabled]).to eq(1)
+ expect(subject[:ingress_modsecurity_not_installed]).to eq(0)
+ end
+ end
+
+ context 'when modsecurity is not installed' do
+ let(:ingress_mode) { :modsecurity_not_installed }
+
+ it 'gathers ingress data' do
+ expect(subject[:ingress_modsecurity_logging]).to eq(0)
+ expect(subject[:ingress_modsecurity_blocking]).to eq(0)
+ expect(subject[:ingress_modsecurity_disabled]).to eq(0)
+ expect(subject[:ingress_modsecurity_not_installed]).to eq(1)
+ end
+ end
+
+ context 'with multiple projects' do
+ let(:environment_2) { create(:environment) }
+ let(:project_2) { environment_2.project }
+ let(:cluster_2) { create(:cluster, environment_scope: environment_scope, projects: [project_2]) }
+ let!(:ingress_2) { create(:clusters_applications_ingress, :modsecurity_logging, cluster: cluster_2) }
+ let!(:deployment_2) { create(:deployment, :success, environment: environment_2, project: project_2, cluster: cluster_2) }
+
+ it 'gathers non-duplicated ingress data' do
+ expect(subject[:ingress_modsecurity_logging]).to eq(1)
+ expect(subject[:ingress_modsecurity_blocking]).to eq(1)
+ expect(subject[:ingress_modsecurity_disabled]).to eq(0)
+ expect(subject[:ingress_modsecurity_not_installed]).to eq(0)
+ end
+ end
+
+ context 'with multiple deployments' do
+ let!(:deployment_2) { create(:deployment, :success, environment: environment, project: project, cluster: cluster) }
+
+ it 'gathers non-duplicated ingress data' do
+ expect(subject[:ingress_modsecurity_logging]).to eq(0)
+ expect(subject[:ingress_modsecurity_blocking]).to eq(1)
+ expect(subject[:ingress_modsecurity_disabled]).to eq(0)
+ expect(subject[:ingress_modsecurity_not_installed]).to eq(0)
+ end
+ end
+
+ context 'with multiple projects' do
+ let(:environment_2) { create(:environment) }
+ let(:project_2) { environment_2.project }
+ let!(:deployment_2) { create(:deployment, :success, environment: environment_2, project: project_2, cluster: cluster) }
+ let(:cluster) { create(:cluster, environment_scope: environment_scope, projects: [project, project_2]) }
+
+ it 'gathers ingress data' do
+ expect(subject[:ingress_modsecurity_logging]).to eq(0)
+ expect(subject[:ingress_modsecurity_blocking]).to eq(2)
+ expect(subject[:ingress_modsecurity_disabled]).to eq(0)
+ expect(subject[:ingress_modsecurity_not_installed]).to eq(0)
+ end
+ end
+
+ context 'with multiple environments' do
+ let!(:environment_2) { create(:environment, project: project) }
+ let!(:deployment_2) { create(:deployment, :success, environment: environment_2, project: project, cluster: cluster) }
+
+ it 'gathers ingress data' do
+ expect(subject[:ingress_modsecurity_logging]).to eq(0)
+ expect(subject[:ingress_modsecurity_blocking]).to eq(2)
+ expect(subject[:ingress_modsecurity_disabled]).to eq(0)
+ expect(subject[:ingress_modsecurity_not_installed]).to eq(0)
+ end
+ end
end
end
@@ -334,9 +560,10 @@ describe Gitlab::UsageData, :aggregate_failures do
end
it 'returns the fallback value when counting fails' do
+ stub_const("Gitlab::UsageData::FALLBACK", 15)
allow(relation).to receive(:count).and_raise(ActiveRecord::StatementInvalid.new(''))
- expect(described_class.count(relation, fallback: 15, batch: false)).to eq(15)
+ expect(described_class.count(relation, batch: false)).to eq(15)
end
end
@@ -350,9 +577,10 @@ describe Gitlab::UsageData, :aggregate_failures do
end
it 'returns the fallback value when counting fails' do
+ stub_const("Gitlab::UsageData::FALLBACK", 15)
allow(relation).to receive(:distinct_count_by).and_raise(ActiveRecord::StatementInvalid.new(''))
- expect(described_class.distinct_count(relation, fallback: 15, batch: false)).to eq(15)
+ expect(described_class.distinct_count(relation, batch: false)).to eq(15)
end
end
end
@@ -387,4 +615,28 @@ describe Gitlab::UsageData, :aggregate_failures do
expect(described_class.alt_usage_data(1)).to eq 1
end
end
+
+ describe '#redis_usage_data' do
+ context 'with block given' do
+ it 'returns the fallback when it gets an error' do
+ expect(described_class.redis_usage_data { raise ::Redis::CommandError } ).to eq(-1)
+ end
+
+ it 'returns the evaluated block when given' do
+ expect(described_class.redis_usage_data { 1 }).to eq(1)
+ end
+ end
+
+ context 'with counter given' do
+ it 'returns the falback values for all counter keys when it gets an error' do
+ allow(::Gitlab::UsageDataCounters::WikiPageCounter).to receive(:totals).and_raise(::Redis::CommandError)
+ expect(described_class.redis_usage_data(::Gitlab::UsageDataCounters::WikiPageCounter)).to eql(::Gitlab::UsageDataCounters::WikiPageCounter.fallback_totals)
+ end
+
+ it 'returns the totals when couter is given' do
+ allow(::Gitlab::UsageDataCounters::WikiPageCounter).to receive(:totals).and_return({ wiki_pages_create: 2 })
+ expect(described_class.redis_usage_data(::Gitlab::UsageDataCounters::WikiPageCounter)).to eql({ wiki_pages_create: 2 })
+ end
+ end
+ end
end