Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/lib/gitlab/usage_data_concerns/topology_spec.rb')
-rw-r--r--spec/lib/gitlab/usage_data_concerns/topology_spec.rb220
1 files changed, 220 insertions, 0 deletions
diff --git a/spec/lib/gitlab/usage_data_concerns/topology_spec.rb b/spec/lib/gitlab/usage_data_concerns/topology_spec.rb
new file mode 100644
index 00000000000..0428900690c
--- /dev/null
+++ b/spec/lib/gitlab/usage_data_concerns/topology_spec.rb
@@ -0,0 +1,220 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::UsageDataConcerns::Topology do
+ include UsageDataHelpers
+
+ describe '#topology_usage_data' do
+ subject { Class.new.extend(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
+
+ context 'when embedded Prometheus server is enabled' do
+ before do
+ expect(Gitlab::Prometheus::Internal).to receive(:prometheus_enabled?).and_return(true)
+ expect(Gitlab::Prometheus::Internal).to receive(:uri).and_return('http://prom:9090')
+ end
+
+ it 'contains a topology element' do
+ allow_prometheus_queries
+
+ expect(subject).to have_key(:topology)
+ end
+
+ context 'tracking node metrics' do
+ it 'contains node level metrics for each instance' do
+ expect_prometheus_api_to(
+ receive_node_memory_query,
+ receive_node_cpu_count_query,
+ receive_node_service_memory_query,
+ receive_node_service_process_count_query
+ )
+
+ expect(subject[:topology]).to eq({
+ duration_s: 0,
+ nodes: [
+ {
+ node_memory_total_bytes: 512,
+ node_cpus: 8,
+ node_services: [
+ {
+ name: 'web',
+ process_count: 10,
+ process_memory_rss: 300,
+ process_memory_uss: 301,
+ process_memory_pss: 302
+ },
+ {
+ name: 'sidekiq',
+ process_count: 5,
+ process_memory_rss: 303
+ }
+ ]
+ },
+ {
+ node_memory_total_bytes: 1024,
+ node_cpus: 16,
+ node_services: [
+ {
+ name: 'sidekiq',
+ process_count: 15,
+ process_memory_rss: 400,
+ process_memory_pss: 401
+ },
+ {
+ name: 'redis',
+ process_count: 1,
+ process_memory_rss: 402
+ }
+ ]
+ }
+ ]
+ })
+ end
+ end
+
+ context 'and some node memory metrics are missing' do
+ it 'removes the respective entries' do
+ expect_prometheus_api_to(
+ receive_node_memory_query(result: []),
+ receive_node_cpu_count_query,
+ receive_node_service_memory_query,
+ receive_node_service_process_count_query
+ )
+
+ keys = subject[:topology][:nodes].flat_map(&:keys)
+ expect(keys).not_to include(:node_memory_total_bytes)
+ expect(keys).to include(:node_cpus, :node_services)
+ end
+ end
+
+ context 'and no results are found' do
+ it 'does not report anything' do
+ expect_prometheus_api_to receive(:aggregate).at_least(:once).and_return({})
+
+ expect(subject[:topology]).to eq({
+ duration_s: 0,
+ nodes: []
+ })
+ end
+ end
+
+ context 'and a connection error is raised' do
+ it 'does not report anything' do
+ expect_prometheus_api_to receive(:aggregate).and_raise('Connection failed')
+
+ expect(subject[:topology]).to eq({ duration_s: 0 })
+ end
+ end
+ end
+
+ context 'when embedded Prometheus server is disabled' do
+ it 'does not report anything' do
+ expect(Gitlab::Prometheus::Internal).to receive(:prometheus_enabled?).and_return(false)
+
+ expect(subject[:topology]).to eq({ duration_s: 0 })
+ end
+ end
+ end
+
+ def receive_node_memory_query(result: nil)
+ receive(:query)
+ .with(/node_memory_MemTotal_bytes/, an_instance_of(Hash))
+ .and_return(result || [
+ {
+ 'metric' => { 'instance' => 'instance1:8080' },
+ 'value' => [1000, '512']
+ },
+ {
+ 'metric' => { 'instance' => 'instance2:8090' },
+ 'value' => [1000, '1024']
+ }
+ ])
+ end
+
+ def receive_node_cpu_count_query(result: nil)
+ receive(:query)
+ .with(/node_cpu_seconds_total/, an_instance_of(Hash))
+ .and_return(result || [
+ {
+ 'metric' => { 'instance' => 'instance2:8090' },
+ 'value' => [1000, '16']
+ },
+ {
+ 'metric' => { 'instance' => 'instance1:8080' },
+ 'value' => [1000, '8']
+ }
+ ])
+ end
+
+ def receive_node_service_memory_query(result: nil)
+ receive(:query)
+ .with(/process_.+_memory_bytes/, an_instance_of(Hash))
+ .and_return(result || [
+ # instance 1: runs Puma + a small Sidekiq
+ {
+ 'metric' => { 'instance' => 'instance1:8080', 'job' => 'gitlab-rails', '__name__' => 'ruby_process_resident_memory_bytes' },
+ 'value' => [1000, '300']
+ },
+ {
+ 'metric' => { 'instance' => 'instance1:8080', 'job' => 'gitlab-rails', '__name__' => 'ruby_process_unique_memory_bytes' },
+ 'value' => [1000, '301']
+ },
+ {
+ 'metric' => { 'instance' => 'instance1:8080', 'job' => 'gitlab-rails', '__name__' => 'ruby_process_proportional_memory_bytes' },
+ 'value' => [1000, '302']
+ },
+ {
+ 'metric' => { 'instance' => 'instance1:8090', 'job' => 'gitlab-sidekiq', '__name__' => 'ruby_process_resident_memory_bytes' },
+ 'value' => [1000, '303']
+ },
+ # instance 2: runs a dedicated Sidekiq + Redis (which uses a different metric name)
+ {
+ 'metric' => { 'instance' => 'instance2:8090', 'job' => 'gitlab-sidekiq', '__name__' => 'ruby_process_resident_memory_bytes' },
+ 'value' => [1000, '400']
+ },
+ {
+ 'metric' => { 'instance' => 'instance2:8090', 'job' => 'gitlab-sidekiq', '__name__' => 'ruby_process_proportional_memory_bytes' },
+ 'value' => [1000, '401']
+ },
+ {
+ 'metric' => { 'instance' => 'instance2:9121', 'job' => 'redis', '__name__' => 'process_resident_memory_bytes' },
+ 'value' => [1000, '402']
+ }
+ ])
+ end
+
+ def receive_node_service_process_count_query(result: nil)
+ receive(:query)
+ .with(/process_start_time_seconds/, an_instance_of(Hash))
+ .and_return(result || [
+ # instance 1
+ {
+ 'metric' => { 'instance' => 'instance1:8080', 'job' => 'gitlab-rails' },
+ 'value' => [1000, '10']
+ },
+ {
+ 'metric' => { 'instance' => 'instance1:8090', 'job' => 'gitlab-sidekiq' },
+ 'value' => [1000, '5']
+ },
+ # instance 2
+ {
+ 'metric' => { 'instance' => 'instance2:8090', 'job' => 'gitlab-sidekiq' },
+ 'value' => [1000, '15']
+ },
+ {
+ 'metric' => { 'instance' => 'instance2:9121', 'job' => 'redis' },
+ 'value' => [1000, '1']
+ },
+ # unknown service => should be stripped out
+ {
+ 'metric' => { 'instance' => 'instance2:9000', 'job' => 'not-a-gitlab-service' },
+ 'value' => [1000, '42']
+ }
+ ])
+ end
+end