usage_data_spec.rb 26.9 KB
Newer Older
1 2
# frozen_string_literal: true

3 4
require 'spec_helper'

5 6
describe Gitlab::UsageData, :aggregate_failures do
  include UsageDataHelpers
7

8
  before do
9
    stub_usage_data_connections
10
    stub_object_store_settings
11
  end
12

13 14 15 16 17 18 19 20 21 22 23
  describe '#uncached_data' do
    it 'ensures recorded_at is set before any other usage data calculation' do
      %i(alt_usage_data redis_usage_data distinct_count count).each do |method|
        expect(described_class).not_to receive(method)
      end
      expect(described_class).to receive(:recorded_at).and_raise(Exception.new('Stopped calculating recorded_at'))

      expect { described_class.uncached_data }.to raise_error('Stopped calculating recorded_at')
    end
  end

24 25
  describe '#data' do
    let!(:ud) { build(:usage_data) }
26

27 28 29
    before do
      allow(described_class).to receive(:grafana_embed_usage_data).and_return(2)
    end
30

31
    subject { described_class.data }
32

33 34 35
    it 'gathers usage data' do
      expect(subject.keys).to include(*UsageDataHelpers::USAGE_DATA_KEYS)
    end
36

37 38
    it 'gathers usage counts' do
      count_data = subject[:counts]
39

40 41 42 43 44 45
      expect(count_data[:boards]).to eq(1)
      expect(count_data[:projects]).to eq(4)
      expect(count_data.values_at(*UsageDataHelpers::SMAU_KEYS)).to all(be_an(Integer))
      expect(count_data.keys).to include(*UsageDataHelpers::COUNTS_KEYS)
      expect(UsageDataHelpers::COUNTS_KEYS - count_data.keys).to be_empty
    end
46

47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
    it 'gathers projects data correctly' do
      count_data = subject[:counts]

      expect(count_data[:projects]).to eq(4)
      expect(count_data[:projects_asana_active]).to eq(0)
      expect(count_data[:projects_prometheus_active]).to eq(1)
      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)
      expect(count_data[:projects_slack_slash_commands_active]).to eq(1)
      expect(count_data[:projects_custom_issue_tracker_active]).to eq(1)
      expect(count_data[:projects_mattermost_active]).to eq(0)
      expect(count_data[:projects_with_repositories_enabled]).to eq(3)
      expect(count_data[:projects_with_error_tracking_enabled]).to eq(1)
      expect(count_data[:projects_with_alerts_service_enabled]).to eq(1)
      expect(count_data[:projects_with_prometheus_alerts]).to eq(2)
      expect(count_data[:projects_with_terraform_reports]).to eq(2)
      expect(count_data[:projects_with_terraform_states]).to eq(2)
71
      expect(count_data[:terraform_reports]).to eq(6)
72 73 74 75 76 77 78
      expect(count_data[:terraform_states]).to eq(3)
      expect(count_data[:issues_created_from_gitlab_error_tracking_ui]).to eq(1)
      expect(count_data[:issues_with_associated_zoom_link]).to eq(2)
      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)
79 80
      expect(count_data[:issues_created_from_alerts]).to eq(3)
      expect(count_data[:issues_created_manually_from_alerts]).to eq(1)
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
      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)
      expect(count_data[:group_clusters_enabled]).to eq(1)
      expect(count_data[:instance_clusters_enabled]).to eq(1)
      expect(count_data[:clusters_disabled]).to eq(3)
      expect(count_data[:project_clusters_disabled]).to eq(1)
      expect(count_data[:group_clusters_disabled]).to eq(1)
      expect(count_data[:instance_clusters_disabled]).to eq(1)
      expect(count_data[:clusters_platforms_eks]).to eq(1)
      expect(count_data[:clusters_platforms_gke]).to eq(1)
      expect(count_data[:clusters_platforms_user]).to eq(1)
      expect(count_data[:clusters_applications_helm]).to eq(1)
      expect(count_data[:clusters_applications_ingress]).to eq(1)
      expect(count_data[:clusters_applications_cert_managers]).to eq(1)
      expect(count_data[:clusters_applications_crossplane]).to eq(1)
      expect(count_data[:clusters_applications_prometheus]).to eq(1)
      expect(count_data[:clusters_applications_runner]).to eq(1)
      expect(count_data[:clusters_applications_knative]).to eq(1)
      expect(count_data[:clusters_applications_elastic_stack]).to eq(1)
      expect(count_data[:grafana_integrated_projects]).to eq(2)
      expect(count_data[:clusters_applications_jupyter]).to eq(1)
      expect(count_data[:clusters_management_project]).to eq(1)
    end
107

108 109 110 111 112 113 114 115 116
    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
117

118 119 120 121
    it 'gathers topology data' do
      expect(subject.keys).to include(:topology)
    end

122 123 124
    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) }
125

126 127 128
      %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) }
129
        end
130
      end
131

132 133
      let_it_be('container_expiration_policy_with_keep_n_set_to_null') { create(:container_expiration_policy, keep_n: nil) }
      let_it_be('container_expiration_policy_with_older_than_set_to_null') { create(:container_expiration_policy, older_than: nil) }
134

135 136
      let(:inactive_policies) { ::ContainerExpirationPolicy.where(enabled: false) }
      let(:active_policies) { ::ContainerExpirationPolicy.active }
137

138
      subject { described_class.data[:counts] }
139

140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
      it 'gathers usage data' do
        expect(subject[:projects_with_expiration_policy_enabled]).to eq 22
        expect(subject[:projects_with_expiration_policy_disabled]).to eq 1

        expect(subject[:projects_with_expiration_policy_enabled_with_keep_n_unset]).to eq 1
        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 16
        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 1
        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 18

        expect(subject[:projects_with_expiration_policy_enabled_with_cadence_set_to_1d]).to eq 18
        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
162
      end
163
    end
164

165 166 167
    it 'works when queries time out' do
      allow_any_instance_of(ActiveRecord::Relation)
        .to receive(:count).and_raise(ActiveRecord::StatementInvalid.new(''))
168

169 170
      expect { subject }.not_to raise_error
    end
171

172 173 174
    it 'jira usage works when queries time out' do
      allow_any_instance_of(ActiveRecord::Relation)
        .to receive(:find_in_batches).and_raise(ActiveRecord::StatementInvalid.new(''))
175

176
      expect { described_class.jira_usage }.not_to raise_error
177
    end
178
  end
179

180 181
  describe '#usage_data_counters' do
    subject { described_class.usage_data_counters }
182

183 184
    it { is_expected.to all(respond_to :totals) }
    it { is_expected.to all(respond_to :fallback_totals) }
A
Alex Kalderimis 已提交
185

186 187
    describe 'the results of calling #totals on all objects in the array' do
      subject { described_class.usage_data_counters.map(&:totals) }
A
Alex Kalderimis 已提交
188

189 190 191
      it { is_expected.to all(be_a Hash) }
      it { is_expected.to all(have_attributes(keys: all(be_a Symbol), values: all(be_a Integer))) }
    end
A
Alex Kalderimis 已提交
192

193 194
    describe 'the results of calling #fallback_totals on all objects in the array' do
      subject { described_class.usage_data_counters.map(&:fallback_totals) }
195

196 197 198
      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
199

200 201
    it 'does not have any conflicts' do
      all_keys = subject.flat_map { |counter| counter.totals.keys }
A
Alex Kalderimis 已提交
202

203
      expect(all_keys.size).to eq all_keys.to_set.size
204
    end
205
  end
A
Alex Kalderimis 已提交
206

207 208
  describe '#license_usage_data' do
    subject { described_class.license_usage_data }
209

210 211 212 213 214 215
    it 'gathers license data' do
      expect(subject[:uuid]).to eq(Gitlab::CurrentSettings.uuid)
      expect(subject[:version]).to eq(Gitlab::VERSION)
      expect(subject[:installation_type]).to eq('gitlab-development-kit')
      expect(subject[:active_user_count]).to eq(User.active.size)
      expect(subject[:recorded_at]).to be_a(Time)
216
    end
217
  end
218

219 220
  describe '.recording_ce_finished_at' do
    subject { described_class.recording_ce_finish_data }
221

222 223
    it 'gathers time ce recording finishes at' do
      expect(subject[:recording_ce_finished_at]).to be_a(Time)
224
    end
225
  end
226

227 228 229 230
  context 'when not relying on database records' do
    describe '#features_usage_data_ce' do
      subject { described_class.features_usage_data_ce }

231 232
      it 'gathers feature usage data', :aggregate_failures do
        expect(subject[:instance_auto_devops_enabled]).to eq(Gitlab::CurrentSettings.auto_devops_enabled?)
233 234 235 236 237 238 239 240 241 242 243 244
        expect(subject[:mattermost_enabled]).to eq(Gitlab.config.mattermost.enabled)
        expect(subject[:signup_enabled]).to eq(Gitlab::CurrentSettings.allow_signup?)
        expect(subject[:ldap_enabled]).to eq(Gitlab.config.ldap.enabled)
        expect(subject[:gravatar_enabled]).to eq(Gitlab::CurrentSettings.gravatar_enabled?)
        expect(subject[:omniauth_enabled]).to eq(Gitlab::Auth.omniauth_enabled?)
        expect(subject[:reply_by_email_enabled]).to eq(Gitlab::IncomingEmail.enabled?)
        expect(subject[:container_registry_enabled]).to eq(Gitlab.config.registry.enabled)
        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
245

246 247 248
      context 'with embedded grafana' do
        it 'returns true when embedded grafana is enabled' do
          stub_application_setting(grafana_enabled: true)
249

250
          expect(subject[:grafana_link_enabled]).to eq(true)
251 252
        end

253 254
        it 'returns false when embedded grafana is disabled' do
          stub_application_setting(grafana_enabled: false)
255

256
          expect(subject[:grafana_link_enabled]).to eq(false)
257
        end
258 259
      end
    end
260

261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
    describe '#components_usage_data' do
      subject { described_class.components_usage_data }

      it 'gathers basic components usage data' do
        stub_runtime(:puma)

        expect(subject[:app_server][:type]).to eq('puma')
        expect(subject[:gitlab_pages][:enabled]).to eq(Gitlab.config.pages.enabled)
        expect(subject[:gitlab_pages][:version]).to eq(Gitlab::Pages::VERSION)
        expect(subject[:git][:version]).to eq(Gitlab::Git.version)
        expect(subject[:database][:adapter]).to eq(Gitlab::Database.adapter_name)
        expect(subject[:database][:version]).to eq(Gitlab::Database.version)
        expect(subject[:gitaly][:version]).to be_present
        expect(subject[:gitaly][:servers]).to be >= 1
        expect(subject[:gitaly][:clusters]).to be >= 0
        expect(subject[:gitaly][:filesystems]).to be_an(Array)
        expect(subject[:gitaly][:filesystems].first).to be_a(String)
278 279
      end

280 281 282 283 284 285 286
      def stub_runtime(runtime)
        allow(Gitlab::Runtime).to receive(:identify).and_return(runtime)
      end
    end

    describe '#app_server_type' do
      subject { described_class.app_server_type }
287

288 289
      it 'successfully identifies runtime and returns the identifier' do
        expect(Gitlab::Runtime).to receive(:identify).and_return(:runtime_identifier)
290

291 292
        is_expected.to eq('runtime_identifier')
      end
293

294 295
      context 'when runtime is not identified' do
        let(:exception) { Gitlab::Runtime::IdentificationError.new('exception message from runtime identify') }
296

297 298 299 300 301 302
        it 'logs the exception and returns unknown app server type' do
          expect(Gitlab::Runtime).to receive(:identify).and_raise(exception)

          expect(Gitlab::AppLogger).to receive(:error).with(exception.message)
          expect(Gitlab::ErrorTracking).to receive(:track_exception).with(exception)
          expect(subject).to eq('unknown_app_server_type')
303 304
        end
      end
305
    end
306

307 308
    describe '#object_store_config' do
      let(:component) { 'lfs' }
309

310
      subject { described_class.object_store_config(component) }
311

312 313 314
      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 })
315

316
          expect(subject).to eq({ enabled: false })
317
        end
318
      end
319

320 321 322 323 324 325
      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' =>
326
                { 'enabled' => true,
327 328 329 330 331 332 333 334 335
                  '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" } })
336
        end
337
      end
338

339 340 341
      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)
342

343
          expect(subject).to eq({ enabled: -1 })
344 345
        end
      end
346
    end
347

348 349
    describe '#object_store_usage_data' do
      subject { described_class.object_store_usage_data }
350

351 352 353
      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")
354
        end
355 356 357 358 359 360 361 362 363

        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'
          })
364
      end
365
    end
366

367 368
    describe '#cycle_analytics_usage_data' do
      subject { described_class.cycle_analytics_usage_data }
369

370 371 372
      it 'works when queries time out in new' do
        allow(Gitlab::CycleAnalytics::UsageData)
          .to receive(:new).and_raise(ActiveRecord::StatementInvalid.new(''))
373

374 375 376 377 378 379
        expect { subject }.not_to raise_error
      end

      it 'works when queries time out in to_json' do
        allow_any_instance_of(Gitlab::CycleAnalytics::UsageData)
          .to receive(:to_json).and_raise(ActiveRecord::StatementInvalid.new(''))
380

381 382 383
        expect { subject }.not_to raise_error
      end
    end
384

385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
    describe '#ingress_modsecurity_usage' do
      subject { described_class.ingress_modsecurity_usage }

      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)
404 405 406
        end
      end

407 408
      context 'when deployment is unsuccessful' do
        let!(:deployment) { create(:deployment, :failed, environment: environment, project: project, cluster: cluster) }
409

410 411 412 413 414 415 416
        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
417

418 419
      context 'when deployment is successful' do
        let!(:deployment) { create(:deployment, :success, environment: environment, project: project, cluster: cluster) }
420

421
        context 'when modsecurity is in blocking mode' do
422 423
          it 'gathers ingress data' do
            expect(subject[:ingress_modsecurity_logging]).to eq(0)
424
            expect(subject[:ingress_modsecurity_blocking]).to eq(1)
425 426 427 428 429
            expect(subject[:ingress_modsecurity_disabled]).to eq(0)
            expect(subject[:ingress_modsecurity_not_installed]).to eq(0)
          end
        end

430 431
        context 'when modsecurity is in logging mode' do
          let(:ingress_mode) { :modsecurity_logging }
432 433

          it 'gathers ingress data' do
434
            expect(subject[:ingress_modsecurity_logging]).to eq(1)
435 436 437 438 439 440
            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

441 442
        context 'when modsecurity is disabled' do
          let(:ingress_mode) { :modsecurity_disabled }
443

444 445 446 447 448
          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)
449
          end
450
        end
451

452 453
        context 'when modsecurity is not installed' do
          let(:ingress_mode) { :modsecurity_not_installed }
454

455 456 457 458 459
          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)
460
          end
461
        end
462

463 464 465 466 467 468
        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) }
469

470 471 472 473 474
          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)
475
          end
476
        end
477

478 479
        context 'with multiple deployments' do
          let!(:deployment_2) { create(:deployment, :success, environment: environment, project: project, cluster: cluster) }
480

481 482 483 484 485
          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)
486
          end
487
        end
488

489 490 491 492 493
        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]) }
494

495 496 497 498 499
          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)
500
          end
501
        end
502

503 504 505
        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) }
506

507 508 509 510 511
          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)
512
          end
513 514
        end
      end
515
    end
516

517 518
    describe '#grafana_embed_usage_data' do
      subject { described_class.grafana_embed_usage_data }
519

520 521 522 523
      let(:project) { create(:project) }
      let(:description_with_embed) { "Some comment\n\nhttps://grafana.example.com/d/xvAk4q0Wk/go-processes?orgId=1&from=1573238522762&to=1573240322762&var-job=prometheus&var-interval=10m&panelId=1&fullscreen" }
      let(:description_with_unintegrated_embed) { "Some comment\n\nhttps://grafana.exp.com/d/xvAk4q0Wk/go-processes?orgId=1&from=1573238522762&to=1573240322762&var-job=prometheus&var-interval=10m&panelId=1&fullscreen" }
      let(:description_with_non_grafana_inline_metric) { "Some comment\n\n#{Gitlab::Routing.url_helpers.metrics_namespace_project_environment_url(*['foo', 'bar', 12])}" }
524

525 526 527
      shared_examples "zero count" do
        it "does not count the issue" do
          expect(subject).to eq(0)
528
        end
529
      end
530

531 532 533
      context 'with project grafana integration enabled' do
        before do
          create(:grafana_integration, project: project, enabled: true)
534 535
        end

536
        context 'with valid and invalid embeds' do
537
          before do
538 539 540 541 542 543 544 545 546
            # Valid
            create(:issue, project: project, description: description_with_embed)
            create(:issue, project: project, description: description_with_embed)
            # In-Valid
            create(:issue, project: project, description: description_with_unintegrated_embed)
            create(:issue, project: project, description: description_with_non_grafana_inline_metric)
            create(:issue, project: project, description: nil)
            create(:issue, project: project, description: '')
            create(:issue, project: project)
547 548
          end

549 550
          it 'counts only the issues with embeds' do
            expect(subject).to eq(2)
551 552
          end
        end
553
      end
554

555 556 557 558
      context 'with project grafana integration disabled' do
        before do
          create(:grafana_integration, project: project, enabled: false)
        end
559

560 561 562 563
        context 'with one issue having a grafana link in the description and one without' do
          before do
            create(:issue, project: project, description: description_with_embed)
            create(:issue, project: project)
564
          end
565 566

          it_behaves_like('zero count')
567 568
        end
      end
569

570 571 572 573 574 575
      context 'with an un-integrated project' do
        context 'with one issue having a grafana link in the description and one without' do
          before do
            create(:issue, project: project, description: description_with_embed)
            create(:issue, project: project)
          end
576

577 578 579
          it_behaves_like('zero count')
        end
      end
580 581
    end
  end
582

583
  describe '#merge_requests_usage' do
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
    let(:time_period) { { created_at: 2.days.ago..Time.current } }
    let(:merge_request) { create(:merge_request) }
    let(:other_user) { create(:user) }
    let(:another_user) { create(:user) }

    before do
      create(:event, target: merge_request, author: merge_request.author, created_at: 1.day.ago)
      create(:event, target: merge_request, author: merge_request.author, created_at: 1.hour.ago)
      create(:event, target: merge_request, author: merge_request.author, created_at: 3.days.ago)
      create(:event, target: merge_request, author: other_user, created_at: 1.day.ago)
      create(:event, target: merge_request, author: other_user, created_at: 1.hour.ago)
      create(:event, target: merge_request, author: other_user, created_at: 3.days.ago)
      create(:event, target: merge_request, author: another_user, created_at: 4.days.ago)
    end

    it 'returns the distinct count of users using merge requests (via events table) within the specified time period' do
600
      expect(described_class.merge_requests_usage(time_period)).to eq(
601 602 603 604
        merge_requests_users: 2
      )
    end
  end
605
end