usage_data_spec.rb 29.3 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 71 72 73 74 75 76 77 78
    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)
      expect(count_data[:terraform_reports]).to eq(3)
      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
    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) }
121

122 123 124
      %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) }
125
        end
126
      end
127

128 129
      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) }
130

131 132
      let(:inactive_policies) { ::ContainerExpirationPolicy.where(enabled: false) }
      let(:active_policies) { ::ContainerExpirationPolicy.active }
133

134
      subject { described_class.data[:counts] }
135

136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
      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
158
      end
159
    end
160

161 162 163
    it 'works when queries time out' do
      allow_any_instance_of(ActiveRecord::Relation)
        .to receive(:count).and_raise(ActiveRecord::StatementInvalid.new(''))
164

165 166
      expect { subject }.not_to raise_error
    end
167

168 169 170
    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(''))
171

172
      expect { described_class.jira_usage }.not_to raise_error
173
    end
174
  end
175

176 177
  describe '#usage_data_counters' do
    subject { described_class.usage_data_counters }
178

179 180
    it { is_expected.to all(respond_to :totals) }
    it { is_expected.to all(respond_to :fallback_totals) }
A
Alex Kalderimis 已提交
181

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

185 186 187
      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 已提交
188

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

192 193 194
      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
195

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

199
      expect(all_keys.size).to eq all_keys.to_set.size
200
    end
201
  end
A
Alex Kalderimis 已提交
202

203 204
  describe '#license_usage_data' do
    subject { described_class.license_usage_data }
205

206 207 208 209 210 211
    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)
212
    end
213
  end
214

215 216
  describe '.recording_ce_finished_at' do
    subject { described_class.recording_ce_finish_data }
217

218 219
    it 'gathers time ce recording finishes at' do
      expect(subject[:recording_ce_finished_at]).to be_a(Time)
220
    end
221
  end
222

223 224 225 226
  context 'when not relying on database records' do
    describe '#features_usage_data_ce' do
      subject { described_class.features_usage_data_ce }

227 228
      it 'gathers feature usage data', :aggregate_failures do
        expect(subject[:instance_auto_devops_enabled]).to eq(Gitlab::CurrentSettings.auto_devops_enabled?)
229 230 231 232 233 234 235 236 237 238 239 240
        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
241

242 243 244
      context 'with embedded grafana' do
        it 'returns true when embedded grafana is enabled' do
          stub_application_setting(grafana_enabled: true)
245

246
          expect(subject[:grafana_link_enabled]).to eq(true)
247 248
        end

249 250
        it 'returns false when embedded grafana is disabled' do
          stub_application_setting(grafana_enabled: false)
251

252
          expect(subject[:grafana_link_enabled]).to eq(false)
253
        end
254 255
      end
    end
256

257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
    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)
274 275
      end

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

    describe '#topology_usage_data' do
      subject { described_class.topology_usage_data }

      before do
        # this pins down time shifts when benchmarking durations
        allow(Process).to receive(:clock_gettime).and_return(0)
      end
288

289
      context 'when embedded Prometheus server is enabled' do
290
        before do
291 292
          expect(Gitlab::Prometheus::Internal).to receive(:prometheus_enabled?).and_return(true)
          expect(Gitlab::Prometheus::Internal).to receive(:uri).and_return('http://prom:9090')
293 294
        end

295 296
        it 'contains a topology element' do
          allow_prometheus_queries
297

298 299
          expect(subject).to have_key(:topology)
        end
300

301 302 303 304 305 306 307
        context 'tracking node metrics' do
          it 'contains node level metrics for each instance' do
            expect_prometheus_api_to receive(:aggregate)
              .with(func: 'avg', metric: 'node_memory_MemTotal_bytes', by: 'instance')
              .and_return({
                'instance1' => 512,
                'instance2' => 1024
308 309
              })

310 311 312 313 314 315 316 317 318 319 320
            expect(subject[:topology]).to eq({
              duration_s: 0,
              nodes: [
                {
                  node_memory_total_bytes: 512
                },
                {
                  node_memory_total_bytes: 1024
                }
              ]
            })
321
          end
322
        end
323

324 325 326
        context 'and no results are found' do
          it 'does not report anything' do
            expect_prometheus_api_to receive(:aggregate).and_return({})
327

328 329 330 331
            expect(subject[:topology]).to eq({
              duration_s: 0,
              nodes: []
            })
332 333 334
          end
        end

335
        context 'and a connection error is raised' do
336
          it 'does not report anything' do
337 338
            expect_prometheus_api_to receive(:aggregate).and_raise('Connection failed')

339 340 341
            expect(subject[:topology]).to eq({ duration_s: 0 })
          end
        end
342
      end
343

344 345 346
      context 'when embedded Prometheus server is disabled' do
        it 'does not report anything' do
          expect(subject[:topology]).to eq({ duration_s: 0 })
347
        end
348
      end
349

350 351 352
      def expect_prometheus_api_to(receive_matcher)
        expect_next_instance_of(Gitlab::PrometheusClient) do |client|
          expect(client).to receive_matcher
353
        end
354
      end
355

356 357 358 359 360 361
      def allow_prometheus_queries
        allow_next_instance_of(Gitlab::PrometheusClient) do |client|
          allow(client).to receive(:aggregate).and_return({})
        end
      end
    end
362

363 364
    describe '#app_server_type' do
      subject { described_class.app_server_type }
365

366 367
      it 'successfully identifies runtime and returns the identifier' do
        expect(Gitlab::Runtime).to receive(:identify).and_return(:runtime_identifier)
368

369 370
        is_expected.to eq('runtime_identifier')
      end
371

372 373
      context 'when runtime is not identified' do
        let(:exception) { Gitlab::Runtime::IdentificationError.new('exception message from runtime identify') }
374

375 376 377 378 379 380
        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')
381 382
        end
      end
383
    end
384

385 386
    describe '#object_store_config' do
      let(:component) { 'lfs' }
387

388
      subject { described_class.object_store_config(component) }
389

390 391 392
      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 })
393

394
          expect(subject).to eq({ enabled: false })
395
        end
396
      end
397

398 399 400 401 402 403
      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' =>
404
                { 'enabled' => true,
405 406 407 408 409 410 411 412 413
                  '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" } })
414
        end
415
      end
416

417 418 419
      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)
420

421
          expect(subject).to eq({ enabled: -1 })
422 423
        end
      end
424
    end
425

426 427
    describe '#object_store_usage_data' do
      subject { described_class.object_store_usage_data }
428

429 430 431
      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")
432
        end
433 434 435 436 437 438 439 440 441

        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'
          })
442
      end
443
    end
444

445 446
    describe '#cycle_analytics_usage_data' do
      subject { described_class.cycle_analytics_usage_data }
447

448 449 450
      it 'works when queries time out in new' do
        allow(Gitlab::CycleAnalytics::UsageData)
          .to receive(:new).and_raise(ActiveRecord::StatementInvalid.new(''))
451

452 453 454 455 456 457
        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(''))
458

459 460 461
        expect { subject }.not_to raise_error
      end
    end
462

463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
    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)
482 483 484
        end
      end

485 486
      context 'when deployment is unsuccessful' do
        let!(:deployment) { create(:deployment, :failed, environment: environment, project: project, cluster: cluster) }
487

488 489 490 491 492 493 494
        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
495

496 497
      context 'when deployment is successful' do
        let!(:deployment) { create(:deployment, :success, environment: environment, project: project, cluster: cluster) }
498

499
        context 'when modsecurity is in blocking mode' do
500 501
          it 'gathers ingress data' do
            expect(subject[:ingress_modsecurity_logging]).to eq(0)
502
            expect(subject[:ingress_modsecurity_blocking]).to eq(1)
503 504 505 506 507
            expect(subject[:ingress_modsecurity_disabled]).to eq(0)
            expect(subject[:ingress_modsecurity_not_installed]).to eq(0)
          end
        end

508 509
        context 'when modsecurity is in logging mode' do
          let(:ingress_mode) { :modsecurity_logging }
510 511

          it 'gathers ingress data' do
512
            expect(subject[:ingress_modsecurity_logging]).to eq(1)
513 514 515 516 517 518
            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

519 520
        context 'when modsecurity is disabled' do
          let(:ingress_mode) { :modsecurity_disabled }
521

522 523 524 525 526
          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)
527
          end
528
        end
529

530 531
        context 'when modsecurity is not installed' do
          let(:ingress_mode) { :modsecurity_not_installed }
532

533 534 535 536 537
          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)
538
          end
539
        end
540

541 542 543 544 545 546
        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) }
547

548 549 550 551 552
          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)
553
          end
554
        end
555

556 557
        context 'with multiple deployments' do
          let!(:deployment_2) { create(:deployment, :success, environment: environment, project: project, cluster: cluster) }
558

559 560 561 562 563
          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)
564
          end
565
        end
566

567 568 569 570 571
        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]) }
572

573 574 575 576 577
          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)
578
          end
579
        end
580

581 582 583
        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) }
584

585 586 587 588 589
          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)
590
          end
591 592
        end
      end
593
    end
594

595 596
    describe '#grafana_embed_usage_data' do
      subject { described_class.grafana_embed_usage_data }
597

598 599 600 601
      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])}" }
602

603 604 605
      shared_examples "zero count" do
        it "does not count the issue" do
          expect(subject).to eq(0)
606
        end
607
      end
608

609 610 611
      context 'with project grafana integration enabled' do
        before do
          create(:grafana_integration, project: project, enabled: true)
612 613
        end

614
        context 'with valid and invalid embeds' do
615
          before do
616 617 618 619 620 621 622 623 624
            # 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)
625 626
          end

627 628
          it 'counts only the issues with embeds' do
            expect(subject).to eq(2)
629 630
          end
        end
631
      end
632

633 634 635 636
      context 'with project grafana integration disabled' do
        before do
          create(:grafana_integration, project: project, enabled: false)
        end
637

638 639 640 641
        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)
642
          end
643 644

          it_behaves_like('zero count')
645 646
        end
      end
647

648 649 650 651 652 653
      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
654

655 656 657
          it_behaves_like('zero count')
        end
      end
658 659
    end
  end
660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682

  describe '#merge_requests_usage_data' do
    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
      expect(described_class.merge_requests_usage_data(time_period)).to eq(
        merge_requests_users: 2
      )
    end
  end
683
end