diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-10-10 15:06:19 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-10-10 15:06:19 +0300 |
commit | 69849c280c5525d132ebaddb1200c390a42ecc06 (patch) | |
tree | 2c6ffc6fd6dc4fa719305f25b475391730389747 /spec | |
parent | c157f963db87a40a3ba7b94b339530ee83194bc8 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r-- | spec/controllers/projects/grafana_api_controller_spec.rb | 97 | ||||
-rw-r--r-- | spec/controllers/projects/merge_requests/diffs_controller_spec.rb | 130 | ||||
-rw-r--r-- | spec/lib/google_api/cloud_platform/client_spec.rb | 3 | ||||
-rw-r--r-- | spec/lib/grafana/client_spec.rb | 107 | ||||
-rw-r--r-- | spec/migrations/schedule_pages_metadata_migration_spec.rb | 29 | ||||
-rw-r--r-- | spec/serializers/diffs_metadata_entity_spec.rb | 46 | ||||
-rw-r--r-- | spec/services/grafana/proxy_service_spec.rb | 139 |
7 files changed, 551 insertions, 0 deletions
diff --git a/spec/controllers/projects/grafana_api_controller_spec.rb b/spec/controllers/projects/grafana_api_controller_spec.rb new file mode 100644 index 00000000000..352a364295b --- /dev/null +++ b/spec/controllers/projects/grafana_api_controller_spec.rb @@ -0,0 +1,97 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Projects::GrafanaApiController do + let_it_be(:project) { create(:project) } + let_it_be(:user) { create(:user) } + + before do + project.add_reporter(user) + sign_in(user) + end + + describe 'GET #proxy' do + let(:proxy_service) { instance_double(Grafana::ProxyService) } + let(:params) do + { + namespace_id: project.namespace.full_path, + project_id: project.name, + proxy_path: 'api/v1/query_range', + datasource_id: '1', + query: 'rate(relevant_metric)', + start: '1570441248', + end: '1570444848', + step: '900' + } + end + + before do + allow(Grafana::ProxyService).to receive(:new).and_return(proxy_service) + allow(proxy_service).to receive(:execute).and_return(service_result) + end + + shared_examples_for 'error response' do |http_status| + it "returns #{http_status}" do + get :proxy, params: params + + expect(response).to have_gitlab_http_status(http_status) + expect(json_response['status']).to eq('error') + expect(json_response['message']).to eq('error message') + end + end + + context 'with a successful result' do + let(:service_result) { { status: :success, body: '{}' } } + + it 'returns a grafana datasource response' do + get :proxy, params: params + + expect(Grafana::ProxyService) + .to have_received(:new) + .with(project, '1', 'api/v1/query_range', + params.slice(:query, :start, :end, :step).stringify_keys) + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to eq({}) + end + end + + context 'when the request is still unavailable' do + let(:service_result) { nil } + + it 'returns 204 no content' do + get :proxy, params: params + + expect(response).to have_gitlab_http_status(:no_content) + expect(json_response['status']).to eq('processing') + expect(json_response['message']).to eq('Not ready yet. Try again later.') + end + end + + context 'when an error has occurred' do + context 'with an error accessing grafana' do + let(:service_result) do + { + http_status: :service_unavailable, + status: :error, + message: 'error message' + } + end + + it_behaves_like 'error response', :service_unavailable + end + + context 'with a processing error' do + let(:service_result) do + { + status: :error, + message: 'error message' + } + end + + it_behaves_like 'error response', :bad_request + end + end + end +end diff --git a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb index 302de3246c2..e677e836145 100644 --- a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb @@ -100,6 +100,136 @@ describe Projects::MergeRequests::DiffsController do it_behaves_like 'persisted preferred diff view cookie' end + describe 'GET diffs_metadata' do + def go(extra_params = {}) + params = { + namespace_id: project.namespace.to_param, + project_id: project, + id: merge_request.iid, + format: 'json' + } + + get :diffs_metadata, params: params.merge(extra_params) + end + + context 'when not authorized' do + let(:another_user) { create(:user) } + + before do + sign_in(another_user) + end + + it 'returns 404 when not a member' do + go + + expect(response).to have_gitlab_http_status(404) + end + + it 'returns 404 when visibility level is not enough' do + project.add_guest(another_user) + + go + + expect(response).to have_gitlab_http_status(404) + end + end + + context 'when diffable does not exists' do + it 'returns 404' do + go(diff_id: 9999) + + expect(response).to have_gitlab_http_status(404) + end + end + + context 'with valid diff_id' do + it 'returns success' do + go(diff_id: merge_request.merge_request_diff.id) + + expect(response).to have_gitlab_http_status(200) + end + + it 'serializes diffs metadata with expected arguments' do + expected_options = { + environment: nil, + merge_request: merge_request, + merge_request_diff: merge_request.merge_request_diff, + merge_request_diffs: merge_request.merge_request_diffs, + start_version: nil, + start_sha: nil, + commit: nil, + latest_diff: true + } + + expect_next_instance_of(DiffsMetadataSerializer) do |instance| + expect(instance).to receive(:represent) + .with(an_instance_of(Gitlab::Diff::FileCollection::MergeRequestDiff), expected_options) + .and_call_original + end + + go(diff_id: merge_request.merge_request_diff.id) + end + end + + context 'with MR regular diff params' do + it 'returns success' do + go + + expect(response).to have_gitlab_http_status(200) + end + + it 'serializes diffs metadata with expected arguments' do + expected_options = { + environment: nil, + merge_request: merge_request, + merge_request_diff: merge_request.merge_request_diff, + merge_request_diffs: merge_request.merge_request_diffs, + start_version: nil, + start_sha: nil, + commit: nil, + latest_diff: true + } + + expect_next_instance_of(DiffsMetadataSerializer) do |instance| + expect(instance).to receive(:represent) + .with(an_instance_of(Gitlab::Diff::FileCollection::MergeRequestDiff), expected_options) + .and_call_original + end + + go + end + end + + context 'with commit param' do + it 'returns success' do + go(commit_id: merge_request.diff_head_sha) + + expect(response).to have_gitlab_http_status(200) + end + + it 'serializes diffs metadata with expected arguments' do + expected_options = { + environment: nil, + merge_request: merge_request, + merge_request_diff: nil, + merge_request_diffs: merge_request.merge_request_diffs, + start_version: nil, + start_sha: nil, + commit: merge_request.diff_head_commit, + latest_diff: nil + } + + expect_next_instance_of(DiffsMetadataSerializer) do |instance| + expect(instance).to receive(:represent) + .with(an_instance_of(Gitlab::Diff::FileCollection::Commit), expected_options) + .and_call_original + end + + go(commit_id: merge_request.diff_head_sha) + end + end + end + describe 'GET diff_for_path' do def diff_for_path(extra_params = {}) params = { diff --git a/spec/lib/google_api/cloud_platform/client_spec.rb b/spec/lib/google_api/cloud_platform/client_spec.rb index 2253feb376d..91b076c31d6 100644 --- a/spec/lib/google_api/cloud_platform/client_spec.rb +++ b/spec/lib/google_api/cloud_platform/client_spec.rb @@ -102,6 +102,9 @@ describe GoogleApi::CloudPlatform::Client do legacy_abac: { enabled: legacy_abac }, + ip_allocation_policy: { + use_ip_aliases: true + }, addons_config: addons_config } } diff --git a/spec/lib/grafana/client_spec.rb b/spec/lib/grafana/client_spec.rb new file mode 100644 index 00000000000..bd93a3c59a2 --- /dev/null +++ b/spec/lib/grafana/client_spec.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Grafana::Client do + let(:grafana_url) { 'https://grafanatest.com/-/grafana-project' } + let(:token) { 'test-token' } + + subject(:client) { described_class.new(api_url: grafana_url, token: token) } + + shared_examples 'calls grafana api' do + let!(:grafana_api_request) { stub_grafana_request(grafana_api_url) } + + it 'calls grafana api' do + subject + + expect(grafana_api_request).to have_been_requested + end + end + + shared_examples 'no redirects' do + let(:redirect_to) { 'https://redirected.example.com' } + let(:other_url) { 'https://grafana.example.org' } + + let!(:redirected_req_stub) { stub_grafana_request(other_url) } + + let!(:redirect_req_stub) do + stub_grafana_request( + grafana_api_url, + status: 302, + headers: { location: redirect_to } + ) + end + + it 'does not follow redirects' do + expect { subject }.to raise_exception( + Grafana::Client::Error, + 'Grafana response status code: 302' + ) + + expect(redirect_req_stub).to have_been_requested + expect(redirected_req_stub).not_to have_been_requested + end + end + + shared_examples 'handles exceptions' do + exceptions = { + Gitlab::HTTP::Error => 'Error when connecting to Grafana', + Net::OpenTimeout => 'Connection to Grafana timed out', + SocketError => 'Received SocketError when trying to connect to Grafana', + OpenSSL::SSL::SSLError => 'Grafana returned invalid SSL data', + Errno::ECONNREFUSED => 'Connection refused', + StandardError => 'Grafana request failed due to StandardError' + } + + exceptions.each do |exception, message| + context "#{exception}" do + before do + stub_request(:get, grafana_api_url).to_raise(exception) + end + + it do + expect { subject } + .to raise_exception(Grafana::Client::Error, message) + end + end + end + end + + describe '#proxy_datasource' do + let(:grafana_api_url) do + 'https://grafanatest.com/-/grafana-project/' \ + 'api/datasources/proxy/' \ + '1/api/v1/query_range' \ + '?query=rate(relevant_metric)' \ + '&start=1570441248&end=1570444848&step=900' + end + + subject do + client.proxy_datasource( + datasource_id: '1', + proxy_path: 'api/v1/query_range', + query: { + query: 'rate(relevant_metric)', + start: 1570441248, + end: 1570444848, + step: 900 + } + ) + end + + it_behaves_like 'calls grafana api' + it_behaves_like 'no redirects' + it_behaves_like 'handles exceptions' + end + + private + + def stub_grafana_request(url, body: {}, status: 200, headers: {}) + stub_request(:get, url) + .to_return( + status: status, + headers: { 'Content-Type' => 'application/json' }.merge(headers), + body: body.to_json + ) + end +end diff --git a/spec/migrations/schedule_pages_metadata_migration_spec.rb b/spec/migrations/schedule_pages_metadata_migration_spec.rb new file mode 100644 index 00000000000..100ed520a32 --- /dev/null +++ b/spec/migrations/schedule_pages_metadata_migration_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20191002031332_schedule_pages_metadata_migration') + +describe SchedulePagesMetadataMigration, :migration, :sidekiq do + let(:namespaces) { table(:namespaces) } + let(:projects) { table(:projects) } + + before do + stub_const("#{described_class.name}::BATCH_SIZE", 1) + + namespaces.create!(id: 11, name: 'gitlab', path: 'gitlab-org') + projects.create!(id: 111, namespace_id: 11, name: 'Project 111') + projects.create!(id: 114, namespace_id: 11, name: 'Project 114') + end + + it 'schedules pages metadata migration' do + Sidekiq::Testing.fake! do + Timecop.freeze do + migrate! + + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(2.minutes, 111, 111) + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(4.minutes, 114, 114) + expect(BackgroundMigrationWorker.jobs.size).to eq(2) + end + end + end +end diff --git a/spec/serializers/diffs_metadata_entity_spec.rb b/spec/serializers/diffs_metadata_entity_spec.rb new file mode 100644 index 00000000000..aaca393ec27 --- /dev/null +++ b/spec/serializers/diffs_metadata_entity_spec.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe DiffsMetadataEntity do + let(:user) { create(:user) } + let(:project) { create(:project, :repository) } + let(:request) { EntityRequest.new(project: project, current_user: user) } + let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) } + let(:merge_request_diffs) { merge_request.merge_request_diffs } + let(:merge_request_diff) { merge_request_diffs.last } + + let(:entity) do + described_class.new(merge_request_diff.diffs, + request: request, + merge_request: merge_request, + merge_request_diffs: merge_request_diffs) + end + + context 'as json' do + subject { entity.as_json } + + it 'contain only required attributes' do + expect(subject.keys).to contain_exactly( + # Inherited attributes + :real_size, :size, :branch_name, + :target_branch_name, :commit, :merge_request_diff, + :start_version, :latest_diff, :latest_version_path, + :added_lines, :removed_lines, :render_overflow_warning, + :email_patch_path, :plain_diff_path, + :merge_request_diffs, + # Attributes + :diff_files + ) + end + + describe 'diff_files' do + it 'returns diff files metadata' do + payload = + DiffFileMetadataEntity.represent(merge_request_diff.diffs.diff_files).as_json + + expect(subject[:diff_files]).to eq(payload) + end + end + end +end diff --git a/spec/services/grafana/proxy_service_spec.rb b/spec/services/grafana/proxy_service_spec.rb new file mode 100644 index 00000000000..694d531c9fc --- /dev/null +++ b/spec/services/grafana/proxy_service_spec.rb @@ -0,0 +1,139 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Grafana::ProxyService do + include ReactiveCachingHelpers + + let_it_be(:project) { create(:project) } + let_it_be(:grafana_integration) { create(:grafana_integration, project: project) } + + let(:proxy_path) { 'api/v1/query_range' } + let(:datasource_id) { '1' } + let(:query_params) do + { + 'query' => 'rate(relevant_metric)', + 'start' => '1570441248', + 'end' => '1570444848', + 'step' => '900' + } + end + + let(:cache_params) { [project.id, datasource_id, proxy_path, query_params] } + + let(:service) do + described_class.new(project, datasource_id, proxy_path, query_params) + end + + shared_examples_for 'initializes an instance' do + it 'initializes an instance of ProxyService class' do + expect(subject).to be_an_instance_of(described_class) + expect(subject.project).to eq(project) + expect(subject.datasource_id).to eq('1') + expect(subject.proxy_path).to eq('api/v1/query_range') + expect(subject.query_params).to eq(query_params) + end + end + + describe '.from_cache' do + subject { described_class.from_cache(*cache_params) } + + it_behaves_like 'initializes an instance' + end + + describe '#initialize' do + subject { service } + + it_behaves_like 'initializes an instance' + end + + describe '#execute' do + subject(:result) { service.execute } + + context 'when grafana integration is not configured' do + before do + allow(project).to receive(:grafana_integration).and_return(nil) + end + + it 'returns error' do + expect(result).to eq( + status: :error, + message: 'Proxy support for this API is not available currently' + ) + end + end + + context 'with caching', :use_clean_rails_memory_store_caching do + context 'when value not present in cache' do + it 'returns nil' do + expect(ReactiveCachingWorker) + .to receive(:perform_async) + .with(service.class, service.id, *cache_params) + + expect(result).to eq(nil) + end + end + + context 'when value present in cache' do + let(:return_value) { { 'http_status' => 200, 'body' => 'body' } } + + before do + stub_reactive_cache(service, return_value, cache_params) + end + + it 'returns cached value' do + expect(ReactiveCachingWorker) + .not_to receive(:perform_async) + .with(service.class, service.id, *cache_params) + + expect(result[:http_status]).to eq(return_value[:http_status]) + expect(result[:body]).to eq(return_value[:body]) + end + end + end + + context 'call prometheus api' do + let(:client) { service.send(:client) } + + before do + synchronous_reactive_cache(service) + end + + context 'connection to grafana datasource succeeds' do + let(:response) { instance_double(Gitlab::HTTP::Response) } + let(:status_code) { 400 } + let(:body) { 'body' } + + before do + allow(client).to receive(:proxy_datasource).and_return(response) + + allow(response).to receive(:code).and_return(status_code) + allow(response).to receive(:body).and_return(body) + end + + it 'returns the http status code and body from prometheus' do + expect(result).to eq( + http_status: status_code, + body: body, + status: :success + ) + end + end + + context 'connection to grafana datasource fails' do + before do + allow(client).to receive(:proxy_datasource) + .and_raise(Grafana::Client::Error, 'Network connection error') + end + + it 'returns error' do + expect(result).to eq( + status: :error, + message: 'Network connection error', + http_status: :service_unavailable + ) + end + end + end + end +end |