summaryrefslogtreecommitdiff
path: root/spec/requests/api
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-04-20 18:38:24 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-04-20 18:38:24 +0000
commit983a0bba5d2a042c4a3bbb22432ec192c7501d82 (patch)
treeb153cd387c14ba23bd5a07514c7c01fddf6a78a0 /spec/requests/api
parenta2bddee2cdb38673df0e004d5b32d9f77797de64 (diff)
downloadgitlab-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.rb7
-rw-r--r--spec/requests/api/graphql/metrics/dashboard/annotations_spec.rb109
-rw-r--r--spec/requests/api/graphql/mutations/jira_import/start_spec.rb12
-rw-r--r--spec/requests/api/graphql/project/merge_request_spec.rb11
-rw-r--r--spec/requests/api/markdown_spec.rb2
-rw-r--r--spec/requests/api/merge_requests_spec.rb24
-rw-r--r--spec/requests/api/project_statistics_spec.rb8
-rw-r--r--spec/requests/api/projects_spec.rb4
-rw-r--r--spec/requests/api/terraform/state_spec.rb238
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