diff options
author | Andrew Newdigate <andrew@gitlab.com> | 2019-01-07 13:40:54 +0300 |
---|---|---|
committer | Andrew Newdigate <andrew@gitlab.com> | 2019-01-22 19:15:30 +0300 |
commit | ca464b603396693ae992096a4efa05def0fa28e8 (patch) | |
tree | 6ed0a135d8ce5abe17fd9eca2c74c1d64d193ca5 /spec | |
parent | 33a6f23774c0e79f791da1b07dbdd48332467372 (diff) |
Adds inter-service OpenTracing propagation
This change allows the GitLab rails and sidekiq components to receive
tracing spans from upstream services such as Workhorse and pass these
spans on to downstream services including Gitaly and Sidekiq.
This change will also emit traces for incoming and outgoing requests
using the propagated trace information. This will allow operators and
engineers to view traces across the Workhorse, GitLab Rails, Sidekiq and
Gitaly components.
Additional intra-service instrumentation will be added in future
changes.
Diffstat (limited to 'spec')
4 files changed, 195 insertions, 0 deletions
diff --git a/spec/lib/gitlab/tracing/grpc_interceptor_spec.rb b/spec/lib/gitlab/tracing/grpc_interceptor_spec.rb new file mode 100644 index 00000000000..7f5aecb7baa --- /dev/null +++ b/spec/lib/gitlab/tracing/grpc_interceptor_spec.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' + +describe Gitlab::Tracing::GRPCInterceptor do + subject { described_class.instance } + + shared_examples_for "a grpc interceptor method" do + let(:custom_error) { Class.new(StandardError) } + + it 'yields' do + expect { |b| method.call(kwargs, &b) }.to yield_control + end + + it 'propagates exceptions' do + expect { method.call(kwargs) { raise custom_error } }.to raise_error(custom_error) + end + end + + describe '#request_response' do + let(:method) { subject.method(:request_response) } + let(:kwargs) { { request: {}, call: {}, method: 'grc_method', metadata: {} } } + + it_behaves_like 'a grpc interceptor method' + end + + describe '#client_streamer' do + let(:method) { subject.method(:client_streamer) } + let(:kwargs) { { requests: [], call: {}, method: 'grc_method', metadata: {} } } + + it_behaves_like 'a grpc interceptor method' + end + + describe '#server_streamer' do + let(:method) { subject.method(:server_streamer) } + let(:kwargs) { { request: {}, call: {}, method: 'grc_method', metadata: {} } } + + it_behaves_like 'a grpc interceptor method' + end + + describe '#bidi_streamer' do + let(:method) { subject.method(:bidi_streamer) } + let(:kwargs) { { requests: [], call: {}, method: 'grc_method', metadata: {} } } + + it_behaves_like 'a grpc interceptor method' + end +end diff --git a/spec/lib/gitlab/tracing/rack_middleware_spec.rb b/spec/lib/gitlab/tracing/rack_middleware_spec.rb new file mode 100644 index 00000000000..13d4d8a89f7 --- /dev/null +++ b/spec/lib/gitlab/tracing/rack_middleware_spec.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Tracing::RackMiddleware do + using RSpec::Parameterized::TableSyntax + + describe '#call' do + context 'for normal middleware flow' do + let(:fake_app) { -> (env) { fake_app_response } } + subject { described_class.new(fake_app) } + let(:request) { } + + context 'for 200 responses' do + let(:fake_app_response) { [200, { 'Content-Type': 'text/plain' }, ['OK']] } + + it 'delegates correctly' do + expect(subject.call(Rack::MockRequest.env_for("/"))).to eq(fake_app_response) + end + end + + context 'for 500 responses' do + let(:fake_app_response) { [500, { 'Content-Type': 'text/plain' }, ['Error']] } + + it 'delegates correctly' do + expect(subject.call(Rack::MockRequest.env_for("/"))).to eq(fake_app_response) + end + end + end + + context 'when an application is raising an exception' do + let(:custom_error) { Class.new(StandardError) } + let(:fake_app) { ->(env) { raise custom_error } } + + subject { described_class.new(fake_app) } + + it 'delegates propagates exceptions correctly' do + expect { subject.call(Rack::MockRequest.env_for("/")) }.to raise_error(custom_error) + end + end + end + + describe '.build_sanitized_url_from_env' do + def env_for_url(url) + env = Rack::MockRequest.env_for(input_url) + env['action_dispatch.parameter_filter'] = [/token/] + + env + end + + where(:input_url, :output_url) do + '/gitlab-org/gitlab-ce' | 'http://example.org/gitlab-org/gitlab-ce' + '/gitlab-org/gitlab-ce?safe=1' | 'http://example.org/gitlab-org/gitlab-ce?safe=1' + '/gitlab-org/gitlab-ce?private_token=secret' | 'http://example.org/gitlab-org/gitlab-ce?private_token=%5BFILTERED%5D' + '/gitlab-org/gitlab-ce?mixed=1&private_token=secret' | 'http://example.org/gitlab-org/gitlab-ce?mixed=1&private_token=%5BFILTERED%5D' + end + + with_them do + it { expect(described_class.build_sanitized_url_from_env(env_for_url(input_url))).to eq(output_url) } + end + end +end diff --git a/spec/lib/gitlab/tracing/sidekiq/client_middleware_spec.rb b/spec/lib/gitlab/tracing/sidekiq/client_middleware_spec.rb new file mode 100644 index 00000000000..3755860b5ba --- /dev/null +++ b/spec/lib/gitlab/tracing/sidekiq/client_middleware_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' + +describe Gitlab::Tracing::Sidekiq::ClientMiddleware do + describe '#call' do + let(:worker_class) { 'test_worker_class' } + let(:job) do + { + 'class' => "jobclass", + 'queue' => "jobqueue", + 'retry' => 0, + 'args' => %w{1 2 3} + } + end + let(:queue) { 'test_queue' } + let(:redis_pool) { double("redis_pool") } + let(:custom_error) { Class.new(StandardError) } + let(:span) { OpenTracing.start_span('test', ignore_active_scope: true) } + + subject { described_class.new } + + it 'yields' do + expect(subject).to receive(:in_tracing_span).with( + operation_name: "sidekiq:jobclass", + tags: { + "component" => "sidekiq", + "span.kind" => "client", + "sidekiq.queue" => "jobqueue", + "sidekiq.jid" => nil, + "sidekiq.retry" => "0", + "sidekiq.args" => "1, 2, 3" + } + ).and_yield(span) + + expect { |b| subject.call(worker_class, job, queue, redis_pool, &b) }.to yield_control + end + + it 'propagates exceptions' do + expect { subject.call(worker_class, job, queue, redis_pool) { raise custom_error } }.to raise_error(custom_error) + end + end +end diff --git a/spec/lib/gitlab/tracing/sidekiq/server_middleware_spec.rb b/spec/lib/gitlab/tracing/sidekiq/server_middleware_spec.rb new file mode 100644 index 00000000000..c3087de785a --- /dev/null +++ b/spec/lib/gitlab/tracing/sidekiq/server_middleware_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' + +describe Gitlab::Tracing::Sidekiq::ServerMiddleware do + describe '#call' do + let(:worker_class) { 'test_worker_class' } + let(:job) do + { + 'class' => "jobclass", + 'queue' => "jobqueue", + 'retry' => 0, + 'args' => %w{1 2 3} + } + end + let(:queue) { 'test_queue' } + let(:custom_error) { Class.new(StandardError) } + let(:span) { OpenTracing.start_span('test', ignore_active_scope: true) } + subject { described_class.new } + + it 'yields' do + expect(subject).to receive(:in_tracing_span).with( + hash_including( + operation_name: "sidekiq:jobclass", + tags: { + "component" => "sidekiq", + "span.kind" => "server", + "sidekiq.queue" => "jobqueue", + "sidekiq.jid" => nil, + "sidekiq.retry" => "0", + "sidekiq.args" => "1, 2, 3" + } + ) + ).and_yield(span) + + expect { |b| subject.call(worker_class, job, queue, &b) }.to yield_control + end + + it 'propagates exceptions' do + expect { subject.call(worker_class, job, queue) { raise custom_error } }.to raise_error(custom_error) + end + end +end |