diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-20 18:38:24 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-20 18:38:24 +0000 |
commit | 983a0bba5d2a042c4a3bbb22432ec192c7501d82 (patch) | |
tree | b153cd387c14ba23bd5a07514c7c01fddf6a78a0 /spec/requests/api | |
parent | a2bddee2cdb38673df0e004d5b32d9f77797de64 (diff) | |
download | gitlab-ce-983a0bba5d2a042c4a3bbb22432ec192c7501d82.tar.gz |
Add latest changes from gitlab-org/gitlab@12-10-stable-ee
Diffstat (limited to 'spec/requests/api')
-rw-r--r-- | spec/requests/api/deploy_tokens_spec.rb | 7 | ||||
-rw-r--r-- | spec/requests/api/graphql/metrics/dashboard/annotations_spec.rb | 109 | ||||
-rw-r--r-- | spec/requests/api/graphql/mutations/jira_import/start_spec.rb | 12 | ||||
-rw-r--r-- | spec/requests/api/graphql/project/merge_request_spec.rb | 11 | ||||
-rw-r--r-- | spec/requests/api/markdown_spec.rb | 2 | ||||
-rw-r--r-- | spec/requests/api/merge_requests_spec.rb | 24 | ||||
-rw-r--r-- | spec/requests/api/project_statistics_spec.rb | 8 | ||||
-rw-r--r-- | spec/requests/api/projects_spec.rb | 4 | ||||
-rw-r--r-- | spec/requests/api/terraform/state_spec.rb | 238 |
9 files changed, 346 insertions, 69 deletions
diff --git a/spec/requests/api/deploy_tokens_spec.rb b/spec/requests/api/deploy_tokens_spec.rb index 5948c3d719f..499c334d491 100644 --- a/spec/requests/api/deploy_tokens_spec.rb +++ b/spec/requests/api/deploy_tokens_spec.rb @@ -205,10 +205,11 @@ describe API::DeployTokens do context 'deploy token creation' do shared_examples 'creating a deploy token' do |entity, unauthenticated_response| + let(:expires_time) { 1.year.from_now } let(:params) do { name: 'Foo', - expires_at: 1.year.from_now, + expires_at: expires_time, scopes: [ 'read_repository' ], @@ -240,6 +241,10 @@ describe API::DeployTokens do expect(response).to have_gitlab_http_status(:created) expect(response).to match_response_schema('public_api/v4/deploy_token') + expect(json_response['name']).to eq('Foo') + expect(json_response['scopes']).to eq(['read_repository']) + expect(json_response['username']).to eq('Bar') + expect(json_response['expires_at'].to_time.to_i).to eq(expires_time.to_i) end context 'with no optional params given' do diff --git a/spec/requests/api/graphql/metrics/dashboard/annotations_spec.rb b/spec/requests/api/graphql/metrics/dashboard/annotations_spec.rb new file mode 100644 index 00000000000..f5a5f0a9ec2 --- /dev/null +++ b/spec/requests/api/graphql/metrics/dashboard/annotations_spec.rb @@ -0,0 +1,109 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Getting Metrics Dashboard Annotations' do + include GraphqlHelpers + + let_it_be(:project) { create(:project) } + let_it_be(:environment) { create(:environment, project: project) } + let_it_be(:current_user) { create(:user) } + let_it_be(:path) { 'config/prometheus/common_metrics.yml' } + let_it_be(:from) { "2020-04-01T03:29:25Z" } + let_it_be(:to) { Time.zone.now.advance(minutes: 5) } + let_it_be(:annotation) { create(:metrics_dashboard_annotation, environment: environment, dashboard_path: path) } + let_it_be(:annotation_for_different_env) { create(:metrics_dashboard_annotation, dashboard_path: path) } + let_it_be(:annotation_for_different_dashboard) { create(:metrics_dashboard_annotation, environment: environment, dashboard_path: ".gitlab/dashboards/test.yml") } + let_it_be(:to_old_annotation) do + create(:metrics_dashboard_annotation, environment: environment, starting_at: Time.parse(from).advance(minutes: -5), dashboard_path: path) + end + let_it_be(:to_new_annotation) do + create(:metrics_dashboard_annotation, environment: environment, starting_at: to.advance(minutes: 5), dashboard_path: path) + end + + let(:fields) do + <<~QUERY + #{all_graphql_fields_for('MetricsDashboardAnnotation'.classify)} + QUERY + end + + let(:query) do + %( + query { + project(fullPath:"#{project.full_path}") { + environments(name: "#{environment.name}") { + nodes { + metricsDashboard(path: "#{path}"){ + annotations(#{args}){ + nodes { + #{fields} + } + } + } + } + } + } + } + ) + end + + context 'feature flag metrics_dashboard_annotations' do + let(:args) { "from: \"#{from}\", to: \"#{to}\"" } + + before do + project.add_developer(current_user) + end + + context 'is off' do + before do + stub_feature_flags(metrics_dashboard_annotations: false) + post_graphql(query, current_user: current_user) + end + + it 'returns empty nodes array' do + annotations = graphql_data.dig('project', 'environments', 'nodes')[0].dig('metricsDashboard', 'annotations', 'nodes') + + expect(annotations).to be_empty + end + end + + context 'is on' do + before do + stub_feature_flags(metrics_dashboard_annotations: true) + post_graphql(query, current_user: current_user) + end + + it_behaves_like 'a working graphql query' + + it 'returns annotations' do + annotations = graphql_data.dig('project', 'environments', 'nodes')[0].dig('metricsDashboard', 'annotations', 'nodes') + + expect(annotations).to match_array [{ + "description" => annotation.description, + "id" => annotation.to_global_id.to_s, + "panelId" => annotation.panel_xid, + "startingAt" => annotation.starting_at.to_s, + "endingAt" => nil + }] + end + + context 'arguments' do + context 'from is missing' do + let(:args) { "to: \"#{from}\"" } + + it 'returns error' do + post_graphql(query, current_user: current_user) + + expect(graphql_errors[0]).to include("message" => "Field 'annotations' is missing required arguments: from") + end + end + + context 'to is missing' do + let(:args) { "from: \"#{from}\"" } + + it_behaves_like 'a working graphql query' + end + end + end + end +end diff --git a/spec/requests/api/graphql/mutations/jira_import/start_spec.rb b/spec/requests/api/graphql/mutations/jira_import/start_spec.rb index feca89558e3..014da5d1e1a 100644 --- a/spec/requests/api/graphql/mutations/jira_import/start_spec.rb +++ b/spec/requests/api/graphql/mutations/jira_import/start_spec.rb @@ -99,12 +99,6 @@ describe 'Starting a Jira Import' do it_behaves_like 'a mutation that returns errors in the response', errors: ['Jira integration not configured.'] end - context 'when issues feature are disabled' do - let_it_be(:project, reload: true) { create(:project, :issues_disabled) } - - it_behaves_like 'a mutation that returns errors in the response', errors: ['Cannot import because issues are not available in this project.'] - end - context 'when when project has Jira service' do let!(:service) { create(:jira_service, project: project) } @@ -112,6 +106,12 @@ describe 'Starting a Jira Import' do project.reload end + context 'when issues feature are disabled' do + let_it_be(:project, reload: true) { create(:project, :issues_disabled) } + + it_behaves_like 'a mutation that returns errors in the response', errors: ['Cannot import because issues are not available in this project.'] + end + context 'when jira_project_key not provided' do let(:jira_project_key) { '' } diff --git a/spec/requests/api/graphql/project/merge_request_spec.rb b/spec/requests/api/graphql/project/merge_request_spec.rb index a1b3111ff71..8d8c31c335d 100644 --- a/spec/requests/api/graphql/project/merge_request_spec.rb +++ b/spec/requests/api/graphql/project/merge_request_spec.rb @@ -130,4 +130,15 @@ describe 'getting merge request information nested in a project' do expect(merge_requests_graphql_data.size).to eq 2 end end + + context 'when merge request is cannot_be_merged_rechecking' do + before do + merge_request.update!(merge_status: 'cannot_be_merged_rechecking') + end + + it 'returns checking' do + post_graphql(query, current_user: current_user) + expect(merge_request_graphql_data['mergeStatus']).to eq('checking') + end + end end diff --git a/spec/requests/api/markdown_spec.rb b/spec/requests/api/markdown_spec.rb index 9b787e76740..09342b06744 100644 --- a/spec/requests/api/markdown_spec.rb +++ b/spec/requests/api/markdown_spec.rb @@ -3,8 +3,6 @@ require "spec_helper" describe API::Markdown do - RSpec::Matchers.define_negated_matcher :exclude, :include - describe "POST /markdown" do let(:user) {} # No-op. It gets overwritten in the contexts below. diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index a8543c8e282..af2ce7f7aef 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -892,6 +892,7 @@ describe API::MergeRequests do expect(json_response['merge_error']).to eq(merge_request.merge_error) expect(json_response['user']['can_merge']).to be_truthy expect(json_response).not_to include('rebase_in_progress') + expect(json_response['first_contribution']).to be_falsy expect(json_response['has_conflicts']).to be_falsy expect(json_response['blocking_discussions_resolved']).to be_truthy expect(json_response['references']['short']).to eq("!#{merge_request.iid}") @@ -915,6 +916,21 @@ describe API::MergeRequests do expect(json_response).to include('rebase_in_progress') end + context 'when author is not a member without any merged merge requests' do + let(:non_member) { create(:user) } + + before do + merge_request.update(author: non_member) + end + + it 'exposes first_contribution as true' do + get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user) + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['first_contribution']).to be_truthy + end + end + context 'merge_request_metrics' do let(:pipeline) { create(:ci_empty_pipeline) } @@ -1060,6 +1076,14 @@ describe API::MergeRequests do expect(json_response['user']['can_merge']).to be_falsy end + it 'returns `checking` as its merge_status instead of `cannot_be_merged_rechecking`' do + merge_request.update!(merge_status: 'cannot_be_merged_rechecking') + + get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user) + + expect(json_response['merge_status']).to eq 'checking' + end + context 'when merge request is unchecked' do before do merge_request.mark_as_unchecked! diff --git a/spec/requests/api/project_statistics_spec.rb b/spec/requests/api/project_statistics_spec.rb index 5d0b506cc92..1f48c081043 100644 --- a/spec/requests/api/project_statistics_spec.rb +++ b/spec/requests/api/project_statistics_spec.rb @@ -50,13 +50,5 @@ describe API::ProjectStatistics do expect(response).to have_gitlab_http_status(:forbidden) expect(json_response['message']).to eq('403 Forbidden') end - - it 'responds with 404 when daily_statistics_enabled? is false' do - stub_feature_flags(project_daily_statistics: { thing: public_project, enabled: false }) - - get api("/projects/#{public_project.id}/statistics", maintainer) - - expect(response).to have_gitlab_http_status(:not_found) - end end end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 190afb9cda5..853155cea7a 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -2414,7 +2414,8 @@ describe API::Projects do project_param = { container_expiration_policy_attributes: { cadence: '1month', - keep_n: 1 + keep_n: 1, + name_regex_keep: 'foo.*' } } @@ -2424,6 +2425,7 @@ describe API::Projects do expect(json_response['container_expiration_policy']['cadence']).to eq('1month') expect(json_response['container_expiration_policy']['keep_n']).to eq(1) + expect(json_response['container_expiration_policy']['name_regex_keep']).to eq('foo.*') end end diff --git a/spec/requests/api/terraform/state_spec.rb b/spec/requests/api/terraform/state_spec.rb index b0a963db684..88c277f4e08 100644 --- a/spec/requests/api/terraform/state_spec.rb +++ b/spec/requests/api/terraform/state_spec.rb @@ -3,95 +3,231 @@ require 'spec_helper' describe API::Terraform::State do - def auth_header_for(user) - auth_header = ActionController::HttpAuthentication::Basic.encode_credentials( - user.username, - create(:personal_access_token, user: user).token - ) - { 'HTTP_AUTHORIZATION' => auth_header } - end + let_it_be(:project) { create(:project) } + let_it_be(:developer) { create(:user, developer_projects: [project]) } + let_it_be(:maintainer) { create(:user, maintainer_projects: [project]) } + + let!(:state) { create(:terraform_state, :with_file, project: project) } - let!(:project) { create(:project) } - let(:developer) { create(:user) } - let(:maintainer) { create(:user) } - let(:state_name) { 'state' } + let(:current_user) { maintainer } + let(:auth_header) { basic_auth_header(current_user) } + let(:project_id) { project.id } + let(:state_name) { state.name } + let(:state_path) { "/projects/#{project_id}/terraform/state/#{state_name}" } before do - project.add_maintainer(maintainer) + stub_terraform_state_object_storage(Terraform::StateUploader) end describe 'GET /projects/:id/terraform/state/:name' do - it 'returns 401 if user is not authenticated' do - headers = { 'HTTP_AUTHORIZATION' => 'failing_token' } - get api("/projects/#{project.id}/terraform/state/#{state_name}"), headers: headers + subject(:request) { get api(state_path), headers: auth_header } - expect(response).to have_gitlab_http_status(:unauthorized) - end + context 'without authentication' do + let(:auth_header) { basic_auth_header('failing_token') } - it 'returns terraform state belonging to a project of given state name' do - get api("/projects/#{project.id}/terraform/state/#{state_name}"), headers: auth_header_for(maintainer) + it 'returns 401 if user is not authenticated' do + request - expect(response).to have_gitlab_http_status(:not_implemented) - expect(response.body).to eq('not implemented') + expect(response).to have_gitlab_http_status(:unauthorized) + end end - it 'returns not found if the project does not exists' do - get api("/projects/0000/terraform/state/#{state_name}"), headers: auth_header_for(maintainer) + context 'with maintainer permissions' do + let(:current_user) { maintainer } + + it 'returns terraform state belonging to a project of given state name' do + request + + expect(response).to have_gitlab_http_status(:ok) + expect(response.body).to eq(state.file.read) + end + + context 'for a project that does not exist' do + let(:project_id) { '0000' } + + it 'returns not found' do + request - expect(response).to have_gitlab_http_status(:not_found) + expect(response).to have_gitlab_http_status(:not_found) + end + end end - it 'returns forbidden if the user cannot access the state' do - project.add_developer(developer) - get api("/projects/#{project.id}/terraform/state/#{state_name}"), headers: auth_header_for(developer) + context 'with developer permissions' do + let(:current_user) { developer } + + it 'returns forbidden if the user cannot access the state' do + request - expect(response).to have_gitlab_http_status(:forbidden) + expect(response).to have_gitlab_http_status(:forbidden) + end end end describe 'POST /projects/:id/terraform/state/:name' do + let(:params) { { 'instance': 'example-instance' } } + + subject(:request) { post api(state_path), headers: auth_header, as: :json, params: params } + context 'when terraform state with a given name is already present' do - it 'updates the state' do - post api("/projects/#{project.id}/terraform/state/#{state_name}"), - params: '{ "instance": "example-instance" }', - headers: { 'Content-Type' => 'text/plain' }.merge(auth_header_for(maintainer)) + context 'with maintainer permissions' do + let(:current_user) { maintainer } - expect(response).to have_gitlab_http_status(:not_implemented) - expect(response.body).to eq('not implemented') + it 'updates the state' do + expect { request }.to change { Terraform::State.count }.by(0) + + expect(response).to have_gitlab_http_status(:ok) + end end - it 'returns forbidden if the user cannot access the state' do - project.add_developer(developer) - get api("/projects/#{project.id}/terraform/state/#{state_name}"), headers: auth_header_for(developer) + context 'without body' do + let(:params) { nil } - expect(response).to have_gitlab_http_status(:forbidden) + it 'returns no content if no body is provided' do + request + + expect(response).to have_gitlab_http_status(:no_content) + end + end + + context 'with developer permissions' do + let(:current_user) { developer } + + it 'returns forbidden' do + request + + expect(response).to have_gitlab_http_status(:forbidden) + end end end context 'when there is no terraform state of a given name' do - it 'creates a new state' do - post api("/projects/#{project.id}/terraform/state/example2"), - headers: auth_header_for(maintainer), - params: '{ "database": "example-database" }' + let(:state_name) { 'example2' } + + context 'with maintainer permissions' do + let(:current_user) { maintainer } + + it 'creates a new state' do + expect { request }.to change { Terraform::State.count }.by(1) + + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'without body' do + let(:params) { nil } + + it 'returns no content if no body is provided' do + request - expect(response).to have_gitlab_http_status(:not_implemented) - expect(response.body).to eq('not implemented') + expect(response).to have_gitlab_http_status(:no_content) + end + end + + context 'with developer permissions' do + let(:current_user) { developer } + + it 'returns forbidden' do + request + + expect(response).to have_gitlab_http_status(:forbidden) + end end end end describe 'DELETE /projects/:id/terraform/state/:name' do - it 'deletes the state' do - delete api("/projects/#{project.id}/terraform/state/#{state_name}"), headers: auth_header_for(maintainer) + subject(:request) { delete api(state_path), headers: auth_header } + + context 'with maintainer permissions' do + let(:current_user) { maintainer } + + it 'deletes the state' do + expect { request }.to change { Terraform::State.count }.by(-1) - expect(response).to have_gitlab_http_status(:not_implemented) + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'with developer permissions' do + let(:current_user) { developer } + + it 'returns forbidden' do + expect { request }.to change { Terraform::State.count }.by(0) + + expect(response).to have_gitlab_http_status(:forbidden) + end + end + end + + describe 'PUT /projects/:id/terraform/state/:name/lock' do + let(:params) do + { + ID: '123-456', + Version: '0.1', + Operation: 'OperationTypePlan', + Info: '', + Who: "#{current_user.username}", + Created: Time.now.utc.iso8601(6), + Path: '' + } + end + + subject(:request) { post api("#{state_path}/lock"), headers: auth_header, params: params } + + it 'locks the terraform state' do + request + + expect(response).to have_gitlab_http_status(:ok) end + end + + describe 'DELETE /projects/:id/terraform/state/:name/lock' do + before do + state.lock_xid = '123-456' + state.save! + end + + subject(:request) { delete api("#{state_path}/lock"), headers: auth_header, params: params } - it 'returns forbidden if the user cannot access the state' do - project.add_developer(developer) - get api("/projects/#{project.id}/terraform/state/#{state_name}"), headers: auth_header_for(developer) + context 'with the correct lock id' do + let(:params) { { ID: '123-456' } } - expect(response).to have_gitlab_http_status(:forbidden) + it 'removes the terraform state lock' do + request + + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'with no lock id (force-unlock)' do + let(:params) { {} } + + it 'removes the terraform state lock' do + request + + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'with an incorrect lock id' do + let(:params) { { ID: '456-789' } } + + it 'returns an error' do + request + + expect(response).to have_gitlab_http_status(:conflict) + end + end + + context 'with a longer than 255 character lock id' do + let(:params) { { ID: '0' * 256 } } + + it 'returns an error' do + request + + expect(response).to have_gitlab_http_status(:bad_request) + end end end end |