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

3 4 5
require 'spec_helper'

describe Gitlab::UsageData do
6
  let(:projects) { create_list(:project, 4) }
7
  let!(:board) { create(:board, project: projects[0]) }
8 9

  describe '#data' do
10 11
    before do
      create(:jira_service, project: projects[0])
12
      create(:jira_service, :without_properties_callback, project: projects[1])
13
      create(:jira_service, :jira_cloud_service, project: projects[2])
14 15
      create(:jira_service, :without_properties_callback, project: projects[3],
             properties: { url: 'https://mysite.atlassian.net' })
16 17 18 19
      create(:prometheus_service, project: projects[1])
      create(:service, project: projects[0], type: 'SlackSlashCommandsService', active: true)
      create(:service, project: projects[1], type: 'SlackService', active: true)
      create(:service, project: projects[2], type: 'SlackService', active: true)
20
      create(:service, project: projects[2], type: 'MattermostService', active: false)
21
      create(:service, project: projects[2], type: 'MattermostService', active: true, template: true)
22
      create(:service, project: projects[2], type: 'CustomIssueTrackerService', active: true)
L
Logan King 已提交
23 24
      create(:project_error_tracking_setting, project: projects[0])
      create(:project_error_tracking_setting, project: projects[1], enabled: false)
25 26 27 28
      create(:alerts_service, project: projects[0])
      create(:alerts_service, :inactive, project: projects[1])
      create_list(:issue, 2, project: projects[0], author: User.alert_bot)
      create_list(:issue, 2, project: projects[1], author: User.alert_bot)
29 30 31 32 33
      create_list(:issue, 4, project: projects[0])
      create(:zoom_meeting, project: projects[0], issue: projects[0].issues[0], issue_status: :added)
      create_list(:zoom_meeting, 2, project: projects[0], issue: projects[0].issues[1], issue_status: :removed)
      create(:zoom_meeting, project: projects[0], issue: projects[0].issues[2], issue_status: :added)
      create_list(:zoom_meeting, 2, project: projects[0], issue: projects[0].issues[2], issue_status: :removed)
34
      create(:sentry_issue, issue: projects[0].issues[0])
35 36 37 38 39

      # Enabled clusters
      gcp_cluster = create(:cluster_provider_gcp, :created).cluster
      create(:cluster_provider_aws, :created)
      create(:cluster_platform_kubernetes)
40
      create(:cluster, :group)
41 42 43

      # Disabled clusters
      create(:cluster, :disabled)
44 45
      create(:cluster, :group, :disabled)
      create(:cluster, :group, :disabled)
46 47

      # Applications
48 49
      create(:clusters_applications_helm, :installed, cluster: gcp_cluster)
      create(:clusters_applications_ingress, :installed, cluster: gcp_cluster)
J
João Cunha 已提交
50
      create(:clusters_applications_cert_manager, :installed, cluster: gcp_cluster)
51
      create(:clusters_applications_prometheus, :installed, cluster: gcp_cluster)
52
      create(:clusters_applications_crossplane, :installed, cluster: gcp_cluster)
53
      create(:clusters_applications_runner, :installed, cluster: gcp_cluster)
54
      create(:clusters_applications_knative, :installed, cluster: gcp_cluster)
55
      create(:clusters_applications_elastic_stack, :installed, cluster: gcp_cluster)
56
      create(:clusters_applications_jupyter, :installed, cluster: gcp_cluster)
57

58 59 60 61
      create(:grafana_integration, project: projects[0], enabled: true)
      create(:grafana_integration, project: projects[1], enabled: true)
      create(:grafana_integration, project: projects[2], enabled: false)

62 63
      allow(Gitlab::GrafanaEmbedUsageData).to receive(:issue_count).and_return(2)

64
      ProjectFeature.first.update_attribute('repository_access_level', 0)
65 66
    end

67
    subject { described_class.data }
68

69
    it 'gathers usage data', :aggregate_failures do
J
James Lopez 已提交
70
      expect(subject.keys).to include(*%i(
71 72 73
        active_user_count
        counts
        recorded_at
S
Sean McGivern 已提交
74
        edition
75
        version
76
        installation_type
77
        uuid
S
Sean McGivern 已提交
78
        hostname
79 80 81 82 83 84 85
        mattermost_enabled
        signup_enabled
        ldap_enabled
        gravatar_enabled
        omniauth_enabled
        reply_by_email_enabled
        container_registry_enabled
86
        dependency_proxy_enabled
87
        gitlab_shared_runners_enabled
88 89
        gitlab_pages
        git
90
        gitaly
91
        database
92
        avg_cycle_analytics
R
Ryan Cobb 已提交
93 94
        influxdb_metrics_enabled
        prometheus_metrics_enabled
95
        web_ide_clientside_preview_enabled
96
        ingress_modsecurity_enabled
97
      ))
98 99
    end

100
    it 'gathers usage counts' do
101 102 103 104 105 106 107 108 109 110 111 112 113
      smau_keys = %i(
        snippet_create
        snippet_update
        snippet_comment
        merge_request_comment
        merge_request_create
        commit_comment
        wiki_pages_create
        wiki_pages_update
        wiki_pages_delete
        web_ide_views
        web_ide_commits
        web_ide_merge_requests
114
        web_ide_previews
115 116 117 118 119 120
        navbar_searches
        cycle_analytics_views
        productivity_analytics_views
        source_code_pushes
      )

121
      expected_keys = %i(
122
        assignee_lists
123 124
        boards
        ci_builds
125 126
        ci_internal_pipelines
        ci_external_pipelines
127 128
        ci_pipeline_config_auto_devops
        ci_pipeline_config_repository
129 130
        ci_runners
        ci_triggers
131
        ci_pipeline_schedules
132 133
        auto_devops_enabled
        auto_devops_disabled
134 135
        deploy_keys
        deployments
136 137
        successful_deployments
        failed_deployments
138
        environments
139 140
        clusters
        clusters_enabled
141 142
        project_clusters_enabled
        group_clusters_enabled
143
        clusters_disabled
144 145
        project_clusters_disabled
        group_clusters_disabled
146
        clusters_platforms_eks
147 148 149 150
        clusters_platforms_gke
        clusters_platforms_user
        clusters_applications_helm
        clusters_applications_ingress
A
Amit Rathi 已提交
151
        clusters_applications_cert_managers
152
        clusters_applications_prometheus
153
        clusters_applications_crossplane
154
        clusters_applications_runner
155
        clusters_applications_knative
156
        clusters_applications_elastic_stack
157
        clusters_applications_jupyter
158
        in_review_folder
159
        grafana_integrated_projects
160 161
        groups
        issues
162
        issues_created_from_gitlab_error_tracking_ui
163 164
        issues_with_associated_zoom_link
        issues_using_zoom_quick_actions
165
        issues_with_embedded_grafana_charts_approx
166
        incident_issues
167
        keys
168
        label_lists
169 170 171
        labels
        lfs_objects
        merge_requests
172
        milestone_lists
173 174
        milestones
        notes
175
        pool_repositories
176
        projects
177
        projects_imported_from_github
178
        projects_asana_active
179
        projects_jira_active
180 181
        projects_jira_server_active
        projects_jira_cloud_active
182 183
        projects_slack_notifications_active
        projects_slack_slash_active
184 185
        projects_slack_active
        projects_slack_slash_commands_active
186 187
        projects_custom_issue_tracker_active
        projects_mattermost_active
188
        projects_prometheus_active
189
        projects_with_repositories_enabled
L
Logan King 已提交
190
        projects_with_error_tracking_enabled
191
        projects_with_alerts_service_enabled
192 193 194
        pages_domains
        protected_branches
        releases
195
        remote_mirrors
196
        snippets
197
        suggestions
198
        todos
R
Robert Speicher 已提交
199
        uploads
200
        web_hooks
201
      ).push(*smau_keys)
202 203 204 205

      count_data = subject[:counts]

      expect(count_data[:boards]).to eq(1)
206
      expect(count_data[:projects]).to eq(4)
207
      expect(count_data.values_at(*smau_keys)).to all(be_an(Integer))
208 209
      expect(count_data.keys).to include(*expected_keys)
      expect(expected_keys - count_data.keys).to be_empty
210
    end
211

212
    it 'gathers projects data correctly', :aggregate_failures do
213 214
      count_data = subject[:counts]

215
      expect(count_data[:projects]).to eq(4)
216
      expect(count_data[:projects_asana_active]).to eq(0)
217
      expect(count_data[:projects_prometheus_active]).to eq(1)
218
      expect(count_data[:projects_jira_active]).to eq(4)
219
      expect(count_data[:projects_jira_server_active]).to eq(2)
220
      expect(count_data[:projects_jira_cloud_active]).to eq(2)
221 222
      expect(count_data[:projects_slack_notifications_active]).to eq(2)
      expect(count_data[:projects_slack_slash_active]).to eq(1)
223 224
      expect(count_data[:projects_slack_active]).to eq(2)
      expect(count_data[:projects_slack_slash_commands_active]).to eq(1)
225
      expect(count_data[:projects_custom_issue_tracker_active]).to eq(1)
226
      expect(count_data[:projects_mattermost_active]).to eq(0)
227
      expect(count_data[:projects_with_repositories_enabled]).to eq(3)
L
Logan King 已提交
228
      expect(count_data[:projects_with_error_tracking_enabled]).to eq(1)
229
      expect(count_data[:projects_with_alerts_service_enabled]).to eq(1)
230
      expect(count_data[:issues_created_from_gitlab_error_tracking_ui]).to eq(1)
231 232
      expect(count_data[:issues_with_associated_zoom_link]).to eq(2)
      expect(count_data[:issues_using_zoom_quick_actions]).to eq(3)
233
      expect(count_data[:issues_with_embedded_grafana_charts_approx]).to eq(2)
234
      expect(count_data[:incident_issues]).to eq(4)
235

236 237
      expect(count_data[:clusters_enabled]).to eq(4)
      expect(count_data[:project_clusters_enabled]).to eq(3)
238 239 240 241 242
      expect(count_data[:group_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(2)
      expect(count_data[:group_clusters_enabled]).to eq(1)
243
      expect(count_data[:clusters_platforms_eks]).to eq(1)
244 245 246 247
      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)
A
Amit Rathi 已提交
248
      expect(count_data[:clusters_applications_cert_managers]).to eq(1)
249
      expect(count_data[:clusters_applications_crossplane]).to eq(1)
250 251
      expect(count_data[:clusters_applications_prometheus]).to eq(1)
      expect(count_data[:clusters_applications_runner]).to eq(1)
252
      expect(count_data[:clusters_applications_knative]).to eq(1)
253
      expect(count_data[:clusters_applications_elastic_stack]).to eq(1)
254
      expect(count_data[:grafana_integrated_projects]).to eq(2)
255
      expect(count_data[:clusters_applications_jupyter]).to eq(1)
256
    end
257 258 259 260 261 262 263

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

      expect { subject }.not_to raise_error
    end
264 265
  end

A
Alex Kalderimis 已提交
266 267 268 269 270 271 272 273
  describe '#usage_data_counters' do
    subject { described_class.usage_data_counters }

    it { is_expected.to all(respond_to :totals) }

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

274 275
      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))) }
A
Alex Kalderimis 已提交
276 277 278 279 280 281 282 283 284
    end

    it 'does not have any conflicts' do
      all_keys = subject.flat_map { |counter| counter.totals.keys }

      expect(all_keys.size).to eq all_keys.to_set.size
    end
  end

285 286 287
  describe '#features_usage_data_ce' do
    subject { described_class.features_usage_data_ce }

288
    it 'gathers feature usage data', :aggregate_failures do
289 290 291 292
      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?)
293
      expect(subject[:omniauth_enabled]).to eq(Gitlab::Auth.omniauth_enabled?)
294 295
      expect(subject[:reply_by_email_enabled]).to eq(Gitlab::IncomingEmail.enabled?)
      expect(subject[:container_registry_enabled]).to eq(Gitlab.config.registry.enabled)
296
      expect(subject[:dependency_proxy_enabled]).to eq(Gitlab.config.dependency_proxy.enabled)
297
      expect(subject[:gitlab_shared_runners_enabled]).to eq(Gitlab.config.gitlab_ci.shared_runners_enabled)
298
      expect(subject[:web_ide_clientside_preview_enabled]).to eq(Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?)
299 300 301 302 303 304
    end
  end

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

305
    it 'gathers components usage data', :aggregate_failures do
306 307 308 309 310
      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)
311 312 313 314
      expect(subject[:gitaly][:version]).to be_present
      expect(subject[:gitaly][:servers]).to be >= 1
      expect(subject[:gitaly][:filesystems]).to be_an(Array)
      expect(subject[:gitaly][:filesystems].first).to be_a(String)
315 316 317
    end
  end

318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
  describe '#ingress_modsecurity_usage' do
    subject { described_class.ingress_modsecurity_usage }

    it 'gathers variable data' do
      allow_any_instance_of(
        ::Clusters::Applications::IngressModsecurityUsageService
      ).to receive(:execute).and_return(
        {
          ingress_modsecurity_blocking: 1,
          ingress_modsecurity_disabled: 2
        }
      )

      expect(subject[:ingress_modsecurity_blocking]).to eq(1)
      expect(subject[:ingress_modsecurity_disabled]).to eq(2)
    end
  end

336
  describe '#license_usage_data' do
337
    subject { described_class.license_usage_data }
338

339
    it 'gathers license data', :aggregate_failures do
340
      expect(subject[:uuid]).to eq(Gitlab::CurrentSettings.uuid)
341
      expect(subject[:version]).to eq(Gitlab::VERSION)
342
      expect(subject[:installation_type]).to eq('gitlab-development-kit')
343 344 345 346
      expect(subject[:active_user_count]).to eq(User.active.count)
      expect(subject[:recorded_at]).to be_a(Time)
    end
  end
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362

  describe '#count' do
    let(:relation) { double(:relation) }

    it 'returns the count when counting succeeds' do
      allow(relation).to receive(:count).and_return(1)

      expect(described_class.count(relation)).to eq(1)
    end

    it 'returns the fallback value when counting fails' do
      allow(relation).to receive(:count).and_raise(ActiveRecord::StatementInvalid.new(''))

      expect(described_class.count(relation, fallback: 15)).to eq(15)
    end
  end
363 364

  describe '#approximate_counts' do
365
    it 'gets approximate counts for selected models', :aggregate_failures do
366 367 368
      create(:label)

      expect(Gitlab::Database::Count).to receive(:approximate_counts)
369
                                           .with(described_class::APPROXIMATE_COUNT_MODELS).once.and_call_original
370 371 372 373 374 375 376

      counts = described_class.approximate_counts.values

      expect(counts.count).to eq(described_class::APPROXIMATE_COUNT_MODELS.count)
      expect(counts.any? { |count| count < 0 }).to be_falsey
    end

377
    it 'returns default values if counts can not be retrieved', :aggregate_failures do
378 379 380 381
      described_class::APPROXIMATE_COUNT_MODELS.map do |model|
        model.name.underscore.pluralize.to_sym
      end

382
      expect(Gitlab::Database::Count).to receive(:approximate_counts).and_return({})
383 384 385
      expect(described_class.approximate_counts.values.uniq).to eq([-1])
    end
  end
386
end