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

3 4
require 'spec_helper'

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

8
  before do
9
    stub_usage_data_connections
10
    stub_object_store_settings
11
  end
12

13 14 15
  describe '.uncached_data' do
    describe '.usage_activity_by_stage' do
      it 'includes usage_activity_by_stage data' do
16 17 18 19 20 21 22 23
        uncached_data = described_class.uncached_data

        expect(uncached_data).to include(:usage_activity_by_stage)
        expect(uncached_data).to include(:usage_activity_by_stage_monthly)
        expect(uncached_data[:usage_activity_by_stage])
          .to include(:configure, :create, :manage, :monitor, :plan, :release, :verify)
        expect(uncached_data[:usage_activity_by_stage_monthly])
          .to include(:configure, :create, :manage, :monitor, :plan, :release, :verify)
24 25
      end

26
      it 'clears memoized values' do
27
        values = %i(issue_minimum_id issue_maximum_id
28
                    project_minimum_id project_maximum_id
29
                    user_minimum_id user_maximum_id unique_visit_service
30 31 32
                    deployment_minimum_id deployment_maximum_id
                    approval_merge_request_rule_minimum_id
                    approval_merge_request_rule_maximum_id)
33
        values.each do |key|
34 35 36 37 38 39
          expect(described_class).to receive(:clear_memoization).with(key)
        end

        described_class.uncached_data
      end

40 41 42 43 44 45 46
      it 'merge_requests_users is included only in montly counters' do
        uncached_data = described_class.uncached_data

        expect(uncached_data[:usage_activity_by_stage][:create])
          .not_to include(:merge_requests_users)
        expect(uncached_data[:usage_activity_by_stage_monthly][:create])
          .to include(:merge_requests_users)
47
      end
48
    end
49

50 51 52 53 54
    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'))
55

56 57 58
      expect { described_class.uncached_data }.to raise_error('Stopped calculating recorded_at')
    end
  end
59

60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
  describe 'usage_activity_by_stage_package' do
    it 'includes accurate usage_activity_by_stage data' do
      for_defined_days_back do
        create(:project, packages: [create(:package)] )
      end

      expect(described_class.usage_activity_by_stage_package({})).to eq(
        projects_with_packages: 2
      )
      expect(described_class.usage_activity_by_stage_package(described_class.last_28_days_time_period)).to eq(
        projects_with_packages: 1
      )
    end
  end

75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
  describe '.usage_activity_by_stage_configure' do
    it 'includes accurate usage_activity_by_stage data' do
      for_defined_days_back do
        user = create(:user)
        cluster = create(:cluster, user: user)
        create(:clusters_applications_cert_manager, :installed, cluster: cluster)
        create(:clusters_applications_helm, :installed, cluster: cluster)
        create(:clusters_applications_ingress, :installed, cluster: cluster)
        create(:clusters_applications_knative, :installed, cluster: cluster)
        create(:cluster, :disabled, user: user)
        create(:cluster_provider_gcp, :created)
        create(:cluster_provider_aws, :created)
        create(:cluster_platform_kubernetes)
        create(:cluster, :group, :disabled, user: user)
        create(:cluster, :group, user: user)
        create(:cluster, :instance, :disabled, :production_environment)
        create(:cluster, :instance, :production_environment)
        create(:cluster, :management_project)
93 94
      end

95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
      expect(described_class.usage_activity_by_stage_configure({})).to include(
        clusters_applications_cert_managers: 2,
        clusters_applications_helm: 2,
        clusters_applications_ingress: 2,
        clusters_applications_knative: 2,
        clusters_management_project: 2,
        clusters_disabled: 4,
        clusters_enabled: 12,
        clusters_platforms_gke: 2,
        clusters_platforms_eks: 2,
        clusters_platforms_user: 2,
        instance_clusters_disabled: 2,
        instance_clusters_enabled: 2,
        group_clusters_disabled: 2,
        group_clusters_enabled: 2,
        project_clusters_disabled: 2,
        project_clusters_enabled: 10
      )
      expect(described_class.usage_activity_by_stage_configure(described_class.last_28_days_time_period)).to include(
        clusters_applications_cert_managers: 1,
        clusters_applications_helm: 1,
        clusters_applications_ingress: 1,
        clusters_applications_knative: 1,
        clusters_management_project: 1,
        clusters_disabled: 2,
        clusters_enabled: 6,
        clusters_platforms_gke: 1,
        clusters_platforms_eks: 1,
        clusters_platforms_user: 1,
        instance_clusters_disabled: 1,
        instance_clusters_enabled: 1,
        group_clusters_disabled: 1,
        group_clusters_enabled: 1,
        project_clusters_disabled: 1,
        project_clusters_enabled: 5
      )
    end
  end
133

134 135 136 137 138 139 140 141 142 143 144 145 146
  describe 'usage_activity_by_stage_create' do
    it 'includes accurate usage_activity_by_stage data' do
      for_defined_days_back do
        user = create(:user)
        project = create(:project, :repository_private,
                         :test_repo, :remote_mirror, creator: user)
        create(:merge_request, source_project: project)
        create(:deploy_key, user: user)
        create(:key, user: user)
        create(:project, creator: user, disable_overriding_approvers_per_merge_request: true)
        create(:project, creator: user, disable_overriding_approvers_per_merge_request: false)
        create(:remote_mirror, project: project)
        create(:snippet, author: user)
147
      end
148

149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
      expect(described_class.usage_activity_by_stage_create({})).to include(
        deploy_keys: 2,
        keys: 2,
        merge_requests: 2,
        projects_with_disable_overriding_approvers_per_merge_request: 2,
        projects_without_disable_overriding_approvers_per_merge_request: 4,
        remote_mirrors: 2,
        snippets: 2
      )
      expect(described_class.usage_activity_by_stage_create(described_class.last_28_days_time_period)).to include(
        deploy_keys: 1,
        keys: 1,
        merge_requests: 1,
        projects_with_disable_overriding_approvers_per_merge_request: 1,
        projects_without_disable_overriding_approvers_per_merge_request: 2,
        remote_mirrors: 1,
        snippets: 1
      )
    end
  end

  describe 'usage_activity_by_stage_manage' do
    it 'includes accurate usage_activity_by_stage data' do
      stub_config(
        omniauth:
          { providers: omniauth_providers }
      )

      for_defined_days_back do
        user = create(:user)
        create(:event, author: user)
        create(:group_member, user: user)
181 182
      end

183 184 185 186 187 188 189 190 191 192 193 194 195 196
      expect(described_class.usage_activity_by_stage_manage({})).to include(
        events: 2,
        groups: 2,
        users_created: 4,
        omniauth_providers: ['google_oauth2']
      )
      expect(described_class.usage_activity_by_stage_manage(described_class.last_28_days_time_period)).to include(
        events: 1,
        groups: 1,
        users_created: 2,
        omniauth_providers: ['google_oauth2']
      )
    end

197
    it 'includes imports usage data' do
198 199 200
      for_defined_days_back do
        user = create(:user)

201
        %w(gitlab_project gitlab github bitbucket bitbucket_server gitea git manifest fogbugz phabricator).each do |type|
202 203
          create(:project, import_type: type, creator_id: user.id)
        end
204 205 206

        jira_project = create(:project, creator_id: user.id)
        create(:jira_import_state, :finished, project: jira_project)
207 208 209 210 211 212 213 214 215 216 217 218 219
      end

      expect(described_class.usage_activity_by_stage_manage({})).to include(
        {
          projects_imported: {
            gitlab_project: 2,
            gitlab: 2,
            github: 2,
            bitbucket: 2,
            bitbucket_server: 2,
            gitea: 2,
            git: 2,
            manifest: 2
220 221 222 223 224
          },
          issues_imported: {
            jira: 2,
            fogbugz: 2,
            phabricator: 2
225 226 227 228 229 230 231 232 233 234 235 236 237 238
          }
        }
      )
      expect(described_class.usage_activity_by_stage_manage(described_class.last_28_days_time_period)).to include(
        {
          projects_imported: {
            gitlab_project: 1,
            gitlab: 1,
            github: 1,
            bitbucket: 1,
            bitbucket_server: 1,
            gitea: 1,
            git: 1,
            manifest: 1
239 240 241 242 243
          },
          issues_imported: {
            jira: 1,
            fogbugz: 1,
            phabricator: 1
244 245 246 247 248
          }
        }
      )
    end

249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
    def omniauth_providers
      [
        OpenStruct.new(name: 'google_oauth2'),
        OpenStruct.new(name: 'ldapmain'),
        OpenStruct.new(name: 'group_saml')
      ]
    end
  end

  describe 'usage_activity_by_stage_monitor' do
    it 'includes accurate usage_activity_by_stage data' do
      for_defined_days_back do
        user    = create(:user, dashboard: 'operations')
        cluster = create(:cluster, user: user)
        create(:project, creator: user)
        create(:clusters_applications_prometheus, :installed, cluster: cluster)
265 266
      end

267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
      expect(described_class.usage_activity_by_stage_monitor({})).to include(
        clusters: 2,
        clusters_applications_prometheus: 2,
        operations_dashboard_default_dashboard: 2
      )
      expect(described_class.usage_activity_by_stage_monitor(described_class.last_28_days_time_period)).to include(
        clusters: 1,
        clusters_applications_prometheus: 1,
        operations_dashboard_default_dashboard: 1
      )
    end
  end

  describe 'usage_activity_by_stage_plan' do
    it 'includes accurate usage_activity_by_stage data' do
      for_defined_days_back do
        user = create(:user)
        project = create(:project, creator: user)
        issue = create(:issue, project: project, author: user)
        create(:issue, project: project, author: User.support_bot)
        create(:note, project: project, noteable: issue, author: user)
        create(:todo, project: project, target: issue, author: user)
289 290
      end

291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
      expect(described_class.usage_activity_by_stage_plan({})).to include(
        issues: 3,
        notes: 2,
        projects: 2,
        todos: 2,
        service_desk_enabled_projects: 2,
        service_desk_issues: 2
      )
      expect(described_class.usage_activity_by_stage_plan(described_class.last_28_days_time_period)).to include(
        issues: 2,
        notes: 1,
        projects: 1,
        todos: 1,
        service_desk_enabled_projects: 1,
        service_desk_issues: 1
      )
    end
  end

  describe 'usage_activity_by_stage_release' do
    it 'includes accurate usage_activity_by_stage data' do
      for_defined_days_back do
        user = create(:user)
        create(:deployment, :failed, user: user)
        create(:release, author: user)
        create(:deployment, :success, user: user)
317
      end
318 319 320 321 322 323 324 325 326 327 328 329 330

      expect(described_class.usage_activity_by_stage_release({})).to include(
        deployments: 2,
        failed_deployments: 2,
        releases: 2,
        successful_deployments: 2
      )
      expect(described_class.usage_activity_by_stage_release(described_class.last_28_days_time_period)).to include(
        deployments: 1,
        failed_deployments: 1,
        releases: 1,
        successful_deployments: 1
      )
331
    end
332
  end
333

334 335 336 337 338 339 340 341 342 343 344 345
  describe 'usage_activity_by_stage_verify' do
    it 'includes accurate usage_activity_by_stage data' do
      for_defined_days_back do
        user = create(:user)
        create(:ci_build, user: user)
        create(:ci_empty_pipeline, source: :external, user: user)
        create(:ci_empty_pipeline, user: user)
        create(:ci_pipeline, :auto_devops_source, user: user)
        create(:ci_pipeline, :repository_source, user: user)
        create(:ci_pipeline_schedule, owner: user)
        create(:ci_trigger, owner: user)
        create(:clusters_applications_runner, :installed)
346 347
      end

348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
      expect(described_class.usage_activity_by_stage_verify({})).to include(
        ci_builds: 2,
        ci_external_pipelines: 2,
        ci_internal_pipelines: 2,
        ci_pipeline_config_auto_devops: 2,
        ci_pipeline_config_repository: 2,
        ci_pipeline_schedules: 2,
        ci_pipelines: 2,
        ci_triggers: 2,
        clusters_applications_runner: 2
      )
      expect(described_class.usage_activity_by_stage_verify(described_class.last_28_days_time_period)).to include(
        ci_builds: 1,
        ci_external_pipelines: 1,
        ci_internal_pipelines: 1,
        ci_pipeline_config_auto_devops: 1,
        ci_pipeline_config_repository: 1,
        ci_pipeline_schedules: 1,
        ci_pipelines: 1,
        ci_triggers: 1,
        clusters_applications_runner: 1
      )
370 371 372
    end
  end

373
  describe '.data' do
374
    let!(:ud) { build(:usage_data) }
375

376 377 378
    before do
      allow(described_class).to receive(:grafana_embed_usage_data).and_return(2)
    end
379

380
    subject { described_class.data }
381

382 383 384
    it 'gathers usage data' do
      expect(subject.keys).to include(*UsageDataHelpers::USAGE_DATA_KEYS)
    end
385

386 387
    it 'gathers usage counts' do
      count_data = subject[:counts]
388

389 390 391 392 393 394
      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
395

396 397 398 399
    it 'gathers usage counts monthly hash' do
      expect(subject[:counts_monthly]).to be_an(Hash)
    end

400
    it 'gathers usage counts correctly' do
401 402 403 404 405 406 407 408 409 410 411 412 413 414
      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_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)
415
      expect(count_data[:projects_mattermost_active]).to eq(1)
416 417
      expect(count_data[:templates_mattermost_active]).to eq(1)
      expect(count_data[:instances_mattermost_active]).to eq(1)
418
      expect(count_data[:projects_inheriting_instance_mattermost_active]).to eq(1)
419 420 421 422 423 424
      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)
425 426
      expect(count_data[:protected_branches]).to eq(2)
      expect(count_data[:protected_branches_except_default]).to eq(1)
427
      expect(count_data[:terraform_reports]).to eq(6)
428 429 430 431 432 433 434
      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)
435 436
      expect(count_data[:issues_created_from_alerts]).to eq(3)
      expect(count_data[:issues_created_manually_from_alerts]).to eq(1)
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
      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)
461
      expect(count_data[:clusters_applications_cilium]).to eq(1)
462
      expect(count_data[:clusters_management_project]).to eq(1)
463 464
      expect(count_data[:kubernetes_agents]).to eq(2)
      expect(count_data[:kubernetes_agents_with_token]).to eq(1)
465

466 467 468
      expect(count_data[:deployments]).to eq(4)
      expect(count_data[:successful_deployments]).to eq(2)
      expect(count_data[:failed_deployments]).to eq(2)
469 470 471
      expect(count_data[:snippets]).to eq(6)
      expect(count_data[:personal_snippets]).to eq(2)
      expect(count_data[:project_snippets]).to eq(4)
472 473

      expect(count_data[:projects_with_packages]).to eq(2)
474
      expect(count_data[:packages]).to eq(3)
475
    end
476

477 478 479 480 481 482 483 484 485
    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
486

487 488 489 490
    it 'gathers topology data' do
      expect(subject.keys).to include(:topology)
    end

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

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

501 502
      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) }
503

504 505
      let(:inactive_policies) { ::ContainerExpirationPolicy.where(enabled: false) }
      let(:active_policies) { ::ContainerExpirationPolicy.active }
506

507
      subject { described_class.data[:counts] }
508

509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
      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
531
      end
532
    end
533

534 535 536
    it 'works when queries time out' do
      allow_any_instance_of(ActiveRecord::Relation)
        .to receive(:count).and_raise(ActiveRecord::StatementInvalid.new(''))
537

538 539
      expect { subject }.not_to raise_error
    end
540

541 542 543 544
    it 'includes a recording_ce_finished_at timestamp' do
      expect(subject[:recording_ce_finished_at]).to be_a(Time)
    end

545 546 547
    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(''))
548

549
      expect { described_class.jira_usage }.not_to raise_error
550
    end
551
  end
552

553 554 555 556 557
  describe '.system_usage_data_monthly' do
    let!(:ud) { build(:usage_data) }

    subject { described_class.system_usage_data_monthly }

558
    it 'gathers monthly usage counts correctly' do
559 560
      counts_monthly = subject[:counts_monthly]

561 562 563
      expect(counts_monthly[:deployments]).to eq(2)
      expect(counts_monthly[:successful_deployments]).to eq(1)
      expect(counts_monthly[:failed_deployments]).to eq(1)
564 565 566
      expect(counts_monthly[:snippets]).to eq(3)
      expect(counts_monthly[:personal_snippets]).to eq(1)
      expect(counts_monthly[:project_snippets]).to eq(2)
567 568 569
    end
  end

570
  describe '.usage_data_counters' do
571
    subject { described_class.usage_data_counters }
572

573 574
    it { is_expected.to all(respond_to :totals) }
    it { is_expected.to all(respond_to :fallback_totals) }
A
Alex Kalderimis 已提交
575

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

579 580 581
      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 已提交
582

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

586 587 588
      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
589

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

593
      expect(all_keys.size).to eq all_keys.to_set.size
594
    end
595
  end
A
Alex Kalderimis 已提交
596

597
  describe '.license_usage_data' do
598
    subject { described_class.license_usage_data }
599

600 601 602 603 604 605
    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)
606
    end
607
  end
608

609
  context 'when not relying on database records' do
610
    describe '.features_usage_data_ce' do
611 612
      subject { described_class.features_usage_data_ce }

613 614
      it 'gathers feature usage data', :aggregate_failures do
        expect(subject[:instance_auto_devops_enabled]).to eq(Gitlab::CurrentSettings.auto_devops_enabled?)
615 616 617 618 619 620 621 622 623 624 625 626
        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
627

628 629 630 631 632 633 634 635 636 637 638 639 640 641
      context 'with embedded Prometheus' do
        it 'returns true when embedded Prometheus is enabled' do
          allow(Gitlab::Prometheus::Internal).to receive(:prometheus_enabled?).and_return(true)

          expect(subject[:prometheus_enabled]).to eq(true)
        end

        it 'returns false when embedded Prometheus is disabled' do
          allow(Gitlab::Prometheus::Internal).to receive(:prometheus_enabled?).and_return(false)

          expect(subject[:prometheus_enabled]).to eq(false)
        end
      end

642 643 644
      context 'with embedded grafana' do
        it 'returns true when embedded grafana is enabled' do
          stub_application_setting(grafana_enabled: true)
645

646
          expect(subject[:grafana_link_enabled]).to eq(true)
647 648
        end

649 650
        it 'returns false when embedded grafana is disabled' do
          stub_application_setting(grafana_enabled: false)
651

652
          expect(subject[:grafana_link_enabled]).to eq(false)
653
        end
654 655
      end
    end
656

657
    describe '.components_usage_data' do
658 659 660
      subject { described_class.components_usage_data }

      it 'gathers basic components usage data' do
661
        stub_application_setting(container_registry_vendor: 'gitlab', container_registry_version: 'x.y.z')
662 663 664 665 666 667 668 669 670 671 672

        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)
673 674
        expect(subject[:container_registry_server][:vendor]).to eq('gitlab')
        expect(subject[:container_registry_server][:version]).to eq('x.y.z')
675
      end
676
    end
677

678
    describe '.object_store_config' do
679
      let(:component) { 'lfs' }
680

681
      subject { described_class.object_store_config(component) }
682

683 684 685
      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 })
686

687
          expect(subject).to eq({ enabled: false })
688
        end
689
      end
690

691 692 693 694 695 696
      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' =>
697
                { 'enabled' => true,
698 699 700 701 702 703 704 705 706
                  '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" } })
707
        end
708
      end
709

710 711 712
      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)
713

714
          expect(subject).to eq({ enabled: -1 })
715 716
        end
      end
717
    end
718

719
    describe '.object_store_usage_data' do
720
      subject { described_class.object_store_usage_data }
721

722 723 724
      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")
725
        end
726 727 728 729 730 731 732 733 734

        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'
          })
735
      end
736
    end
737

738
    describe '.cycle_analytics_usage_data' do
739
      subject { described_class.cycle_analytics_usage_data }
740

741 742 743
      it 'works when queries time out in new' do
        allow(Gitlab::CycleAnalytics::UsageData)
          .to receive(:new).and_raise(ActiveRecord::StatementInvalid.new(''))
744

745 746 747 748 749 750
        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(''))
751

752 753 754
        expect { subject }.not_to raise_error
      end
    end
755

756
    describe '.ingress_modsecurity_usage' do
757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774
      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)
775 776 777
        end
      end

778 779
      context 'when deployment is unsuccessful' do
        let!(:deployment) { create(:deployment, :failed, environment: environment, project: project, cluster: cluster) }
780

781 782 783 784 785 786 787
        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
788

789 790
      context 'when deployment is successful' do
        let!(:deployment) { create(:deployment, :success, environment: environment, project: project, cluster: cluster) }
791

792
        context 'when modsecurity is in blocking mode' do
793 794
          it 'gathers ingress data' do
            expect(subject[:ingress_modsecurity_logging]).to eq(0)
795
            expect(subject[:ingress_modsecurity_blocking]).to eq(1)
796 797 798 799 800
            expect(subject[:ingress_modsecurity_disabled]).to eq(0)
            expect(subject[:ingress_modsecurity_not_installed]).to eq(0)
          end
        end

801 802
        context 'when modsecurity is in logging mode' do
          let(:ingress_mode) { :modsecurity_logging }
803 804

          it 'gathers ingress data' do
805
            expect(subject[:ingress_modsecurity_logging]).to eq(1)
806 807 808 809 810 811
            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

812 813
        context 'when modsecurity is disabled' do
          let(:ingress_mode) { :modsecurity_disabled }
814

815 816 817 818 819
          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)
820
          end
821
        end
822

823 824
        context 'when modsecurity is not installed' do
          let(:ingress_mode) { :modsecurity_not_installed }
825

826 827 828 829 830
          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)
831
          end
832
        end
833

834 835 836 837 838 839
        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) }
840

841 842 843 844 845
          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)
846
          end
847
        end
848

849 850
        context 'with multiple deployments' do
          let!(:deployment_2) { create(:deployment, :success, environment: environment, project: project, cluster: cluster) }
851

852 853 854 855 856
          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)
857
          end
858
        end
859

860 861 862 863 864
        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]) }
865

866 867 868 869 870
          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)
871
          end
872
        end
873

874 875 876
        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) }
877

878 879 880 881 882
          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)
883
          end
884 885
        end
      end
886
    end
887

888
    describe '.grafana_embed_usage_data' do
889
      subject { described_class.grafana_embed_usage_data }
890

891 892 893 894
      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])}" }
895

896 897 898
      shared_examples "zero count" do
        it "does not count the issue" do
          expect(subject).to eq(0)
899
        end
900
      end
901

902 903 904
      context 'with project grafana integration enabled' do
        before do
          create(:grafana_integration, project: project, enabled: true)
905 906
        end

907
        context 'with valid and invalid embeds' do
908
          before do
909 910 911 912 913 914 915 916 917
            # 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)
918 919
          end

920 921
          it 'counts only the issues with embeds' do
            expect(subject).to eq(2)
922 923
          end
        end
924
      end
925

926 927 928 929
      context 'with project grafana integration disabled' do
        before do
          create(:grafana_integration, project: project, enabled: false)
        end
930

931 932 933 934
        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)
935
          end
936 937

          it_behaves_like('zero count')
938 939
        end
      end
940

941 942 943 944 945 946
      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
947

948 949 950
          it_behaves_like('zero count')
        end
      end
951 952
    end
  end
953

954
  describe '.merge_requests_users' do
955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970
    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
971
      expect(described_class.merge_requests_users(time_period)).to eq(2)
972 973
    end
  end
974 975 976 977 978 979 980 981

  def for_defined_days_back(days: [29, 2])
    days.each do |n|
      Timecop.travel(n.days.ago) do
        yield
      end
    end
  end
982

983 984 985 986 987
  describe '#action_monthly_active_users', :clean_gitlab_redis_shared_state do
    let(:time_period) { { created_at: 2.days.ago..time } }
    let(:time) { Time.zone.now }

    before do
988
      counter = Gitlab::UsageDataCounters::TrackUniqueEvents
989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
      project = Event::TARGET_TYPES[:project]
      wiki = Event::TARGET_TYPES[:wiki]
      design = Event::TARGET_TYPES[:design]

      counter.track_event(event_action: :pushed, event_target: project, author_id: 1)
      counter.track_event(event_action: :pushed, event_target: project, author_id: 1)
      counter.track_event(event_action: :pushed, event_target: project, author_id: 2)
      counter.track_event(event_action: :pushed, event_target: project, author_id: 3)
      counter.track_event(event_action: :pushed, event_target: project, author_id: 4, time: time - 3.days)
      counter.track_event(event_action: :created, event_target: project, author_id: 5, time: time - 3.days)
      counter.track_event(event_action: :created, event_target: wiki, author_id: 3)
      counter.track_event(event_action: :created, event_target: design, author_id: 3)
    end

    it 'returns the distinct count of user actions within the specified time period' do
      expect(described_class.action_monthly_active_users(time_period)).to eq(
        {
          action_monthly_active_users_design_management: 1,
          action_monthly_active_users_project_repo: 3,
          action_monthly_active_users_wiki_repo: 1
        }
      )
1011 1012 1013
    end
  end

1014 1015 1016 1017
  describe '.analytics_unique_visits_data' do
    subject { described_class.analytics_unique_visits_data }

    it 'returns the number of unique visits to pages with analytics features' do
1018 1019
      ::Gitlab::Analytics::UniqueVisits.analytics_events.each do |target|
        expect_any_instance_of(::Gitlab::Analytics::UniqueVisits).to receive(:unique_visits_for).with(targets: target).and_return(123)
1020 1021
      end

1022
      expect_any_instance_of(::Gitlab::Analytics::UniqueVisits).to receive(:unique_visits_for).with(targets: :analytics).and_return(543)
1023
      expect_any_instance_of(::Gitlab::Analytics::UniqueVisits).to receive(:unique_visits_for).with(targets: :analytics, start_date: 4.weeks.ago.to_date, end_date: Date.current).and_return(987)
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039

      expect(subject).to eq({
        analytics_unique_visits: {
          'g_analytics_contribution' => 123,
          'g_analytics_insights' => 123,
          'g_analytics_issues' => 123,
          'g_analytics_productivity' => 123,
          'g_analytics_valuestream' => 123,
          'p_analytics_pipelines' => 123,
          'p_analytics_code_reviews' => 123,
          'p_analytics_valuestream' => 123,
          'p_analytics_insights' => 123,
          'p_analytics_issues' => 123,
          'p_analytics_repo' => 123,
          'i_analytics_cohorts' => 123,
          'i_analytics_dev_ops_score' => 123,
1040 1041
          'p_analytics_merge_request' => 123,
          'g_analytics_merge_request' => 123,
1042 1043
          'analytics_unique_visits_for_any_target' => 543,
          'analytics_unique_visits_for_any_target_monthly' => 987
1044 1045 1046 1047
        }
      })
    end
  end
1048

1049 1050 1051 1052 1053 1054 1055
  describe '.compliance_unique_visits_data' do
    subject { described_class.compliance_unique_visits_data }

    before do
      described_class.clear_memoization(:unique_visit_service)

      allow_next_instance_of(::Gitlab::Analytics::UniqueVisits) do |instance|
1056 1057
        ::Gitlab::Analytics::UniqueVisits.compliance_events.each do |target|
          allow(instance).to receive(:unique_visits_for).with(targets: target).and_return(123)
1058 1059 1060 1061
        end

        allow(instance).to receive(:unique_visits_for).with(targets: :compliance).and_return(543)

1062
        allow(instance).to receive(:unique_visits_for).with(targets: :compliance, start_date: 4.weeks.ago.to_date, end_date: Date.current).and_return(987)
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079
      end
    end

    it 'returns the number of unique visits to pages with compliance features' do
      expect(subject).to eq({
        compliance_unique_visits: {
          'g_compliance_dashboard' => 123,
          'g_compliance_audit_events' => 123,
          'i_compliance_credential_inventory' => 123,
          'i_compliance_audit_events' => 123,
          'compliance_unique_visits_for_any_target' => 543,
          'compliance_unique_visits_for_any_target_monthly' => 987
        }
      })
    end
  end

1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
  describe '.search_unique_visits_data' do
    subject { described_class.search_unique_visits_data }

    before do
      described_class.clear_memoization(:unique_visit_service)
      events = ::Gitlab::UsageDataCounters::HLLRedisCounter.events_for_category('search')
      events.each do |event|
        allow(::Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:unique_events).with(event_names: event, start_date: 7.days.ago.to_date, end_date: Date.current).and_return(123)
      end
      allow(::Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:unique_events).with(event_names: events, start_date: 7.days.ago.to_date, end_date: Date.current).and_return(543)
      allow(::Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:unique_events).with(event_names: events, start_date: 4.weeks.ago.to_date, end_date: Date.current).and_return(987)
    end

    it 'returns the number of unique visits to pages with search features' do
      expect(subject).to eq({
        search_unique_visits: {
          'i_search_total' => 123,
          'i_search_advanced' => 123,
          'i_search_paid' => 123,
          'search_unique_visits_for_any_target_weekly' => 543,
          'search_unique_visits_for_any_target_monthly' => 987
        }
      })
    end
  end

1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117
  describe '.service_desk_counts' do
    subject { described_class.send(:service_desk_counts) }

    let(:project) { create(:project, :service_desk_enabled) }

    it 'gathers Service Desk data' do
      create_list(:issue, 2, :confidential, author: User.support_bot, project: project)

      expect(subject).to eq(service_desk_enabled_projects: 1,
                            service_desk_issues: 2)
    end
  end
1118
end