summaryrefslogtreecommitdiff
path: root/spec/requests
diff options
context:
space:
mode:
Diffstat (limited to 'spec/requests')
-rw-r--r--spec/requests/api/award_emoji_spec.rb1
-rw-r--r--spec/requests/api/badges_spec.rb23
-rw-r--r--spec/requests/api/boards_spec.rb1
-rw-r--r--spec/requests/api/branches_spec.rb10
-rw-r--r--spec/requests/api/broadcast_messages_spec.rb22
-rw-r--r--spec/requests/api/deployments_spec.rb93
-rw-r--r--spec/requests/api/files_spec.rb15
-rw-r--r--spec/requests/api/graphql/mutations/award_emojis/add_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/issues/set_confidential_spec.rb51
-rw-r--r--spec/requests/api/graphql/mutations/issues/set_due_date_spec.rb61
-rw-r--r--spec/requests/api/graphql/mutations/snippets/create_spec.rb144
-rw-r--r--spec/requests/api/graphql/mutations/snippets/destroy_spec.rb89
-rw-r--r--spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb63
-rw-r--r--spec/requests/api/graphql/mutations/snippets/update_spec.rb144
-rw-r--r--spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb65
-rw-r--r--spec/requests/api/graphql/mutations/todos/restore_spec.rb97
-rw-r--r--spec/requests/api/graphql/project/error_tracking/sentry_detailed_error_request_spec.rb69
-rw-r--r--spec/requests/api/graphql_spec.rb4
-rw-r--r--spec/requests/api/group_clusters_spec.rb4
-rw-r--r--spec/requests/api/groups_spec.rb50
-rw-r--r--spec/requests/api/helpers_spec.rb26
-rw-r--r--spec/requests/api/internal/base_spec.rb17
-rw-r--r--spec/requests/api/internal/pages_spec.rb11
-rw-r--r--spec/requests/api/issues/get_project_issues_spec.rb18
-rw-r--r--spec/requests/api/issues/issues_spec.rb2
-rw-r--r--spec/requests/api/issues/post_projects_issues_spec.rb4
-rw-r--r--spec/requests/api/jobs_spec.rb8
-rw-r--r--spec/requests/api/keys_spec.rb70
-rw-r--r--spec/requests/api/merge_requests_spec.rb12
-rw-r--r--spec/requests/api/notes_spec.rb2
-rw-r--r--spec/requests/api/pages/pages_spec.rb71
-rw-r--r--spec/requests/api/pipelines_spec.rb16
-rw-r--r--spec/requests/api/project_clusters_spec.rb4
-rw-r--r--spec/requests/api/project_export_spec.rb27
-rw-r--r--spec/requests/api/project_import_spec.rb1
-rw-r--r--spec/requests/api/project_snippets_spec.rb8
-rw-r--r--spec/requests/api/projects_spec.rb1
-rw-r--r--spec/requests/api/releases_spec.rb37
-rw-r--r--spec/requests/api/remote_mirrors_spec.rb41
-rw-r--r--spec/requests/api/runner_spec.rb10
-rw-r--r--spec/requests/api/services_spec.rb10
-rw-r--r--spec/requests/api/settings_spec.rb6
-rw-r--r--spec/requests/api/snippets_spec.rb16
-rw-r--r--spec/requests/api/tags_spec.rb4
-rw-r--r--spec/requests/api/users_spec.rb20
-rw-r--r--spec/requests/git_http_spec.rb2
-rw-r--r--spec/requests/jwt_controller_spec.rb4
-rw-r--r--spec/requests/projects/merge_requests/creations_spec.rb28
-rw-r--r--spec/requests/rack_attack_global_spec.rb28
-rw-r--r--spec/requests/user_avatar_spec.rb36
51 files changed, 1436 insertions, 112 deletions
diff --git a/spec/requests/api/award_emoji_spec.rb b/spec/requests/api/award_emoji_spec.rb
index 80040cddd4d..19a34314bb8 100644
--- a/spec/requests/api/award_emoji_spec.rb
+++ b/spec/requests/api/award_emoji_spec.rb
@@ -9,6 +9,7 @@ describe API::AwardEmoji do
set(:award_emoji) { create(:award_emoji, awardable: issue, user: user) }
let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
let!(:downvote) { create(:award_emoji, :downvote, awardable: merge_request, user: user) }
+
set(:note) { create(:note, project: project, noteable: issue) }
before do
diff --git a/spec/requests/api/badges_spec.rb b/spec/requests/api/badges_spec.rb
index ea0a7d4c9b7..d931dea01e7 100644
--- a/spec/requests/api/badges_spec.rb
+++ b/spec/requests/api/badges_spec.rb
@@ -81,6 +81,7 @@ describe API::Badges do
get api("/#{source_type.pluralize}/#{source.id}/badges/#{badge.id}", user)
expect(response).to have_gitlab_http_status(200)
+ expect(json_response['name']).to eq(badge.name)
expect(json_response['id']).to eq(badge.id)
expect(json_response['link_url']).to eq(badge.link_url)
expect(json_response['rendered_link_url']).to eq(badge.rendered_link_url)
@@ -98,6 +99,7 @@ describe API::Badges do
include_context 'source helpers'
let(:source) { get_source(source_type) }
+ let(:example_name) { 'BadgeName' }
let(:example_url) { 'http://www.example.com' }
let(:example_url2) { 'http://www.example1.com' }
@@ -105,7 +107,7 @@ describe API::Badges do
it_behaves_like 'a 404 response when source is private' do
let(:route) do
post api("/#{source_type.pluralize}/#{source.id}/badges", stranger),
- params: { link_url: example_url, image_url: example_url2 }
+ params: { name: example_name, link_url: example_url, image_url: example_url2 }
end
end
@@ -128,11 +130,12 @@ describe API::Badges do
it 'creates a new badge' do
expect do
post api("/#{source_type.pluralize}/#{source.id}/badges", maintainer),
- params: { link_url: example_url, image_url: example_url2 }
+ params: { name: example_name, link_url: example_url, image_url: example_url2 }
expect(response).to have_gitlab_http_status(201)
end.to change { source.badges.count }.by(1)
+ expect(json_response['name']).to eq(example_name)
expect(json_response['link_url']).to eq(example_url)
expect(json_response['image_url']).to eq(example_url2)
expect(json_response['kind']).to eq source_type
@@ -169,6 +172,7 @@ describe API::Badges do
context "with :sources == #{source_type.pluralize}" do
let(:badge) { source.badges.first }
+ let(:example_name) { 'BadgeName' }
let(:example_url) { 'http://www.example.com' }
let(:example_url2) { 'http://www.example1.com' }
@@ -197,9 +201,10 @@ describe API::Badges do
context 'when authenticated as a maintainer/owner' do
it 'updates the member', :quarantine do
put api("/#{source_type.pluralize}/#{source.id}/badges/#{badge.id}", maintainer),
- params: { link_url: example_url, image_url: example_url2 }
+ params: { name: example_name, link_url: example_url, image_url: example_url2 }
expect(response).to have_gitlab_http_status(200)
+ expect(json_response['name']).to eq(example_name)
expect(json_response['link_url']).to eq(example_url)
expect(json_response['image_url']).to eq(example_url2)
expect(json_response['kind']).to eq source_type
@@ -297,7 +302,7 @@ describe API::Badges do
expect(response).to have_gitlab_http_status(200)
- expect(json_response.keys).to contain_exactly('link_url', 'rendered_link_url', 'image_url', 'rendered_image_url')
+ expect(json_response.keys).to contain_exactly('name', 'link_url', 'rendered_link_url', 'image_url', 'rendered_image_url')
expect(json_response['link_url']).to eq(example_url)
expect(json_response['image_url']).to eq(example_url2)
expect(json_response['rendered_link_url']).to eq(example_url)
@@ -351,9 +356,9 @@ describe API::Badges do
project.add_developer(developer)
project.add_maintainer(maintainer)
project.request_access(access_requester)
- project.project_badges << build(:project_badge, project: project)
- project.project_badges << build(:project_badge, project: project)
- project_group.badges << build(:group_badge, group: group)
+ project.project_badges << build(:project_badge, project: project, name: 'ExampleBadge1')
+ project.project_badges << build(:project_badge, project: project, name: 'ExampleBadge2')
+ project_group.badges << build(:group_badge, group: group, name: 'ExampleBadge3')
end
end
@@ -362,8 +367,8 @@ describe API::Badges do
group.add_developer(developer)
group.add_owner(maintainer)
group.request_access(access_requester)
- group.badges << build(:group_badge, group: group)
- group.badges << build(:group_badge, group: group)
+ group.badges << build(:group_badge, group: group, name: 'ExampleBadge4')
+ group.badges << build(:group_badge, group: group, name: 'ExampleBadge5')
end
end
end
diff --git a/spec/requests/api/boards_spec.rb b/spec/requests/api/boards_spec.rb
index 8a67e956165..510ef9d7d0a 100644
--- a/spec/requests/api/boards_spec.rb
+++ b/spec/requests/api/boards_spec.rb
@@ -69,6 +69,7 @@ describe API::Boards do
set(:group) { create(:group) }
set(:board_parent) { create(:group, parent: group ) }
let(:url) { "/groups/#{board_parent.id}/boards/#{board.id}/lists" }
+
set(:board) { create(:board, group: board_parent) }
it 'creates a new board list for ancestor group labels' do
diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb
index 675b06b057c..99374d28324 100644
--- a/spec/requests/api/branches_spec.rb
+++ b/spec/requests/api/branches_spec.rb
@@ -131,7 +131,7 @@ describe API::Branches do
end
new_branch_name = 'protected-branch'
- CreateBranchService.new(project, current_user).execute(new_branch_name, 'master')
+ ::Branches::CreateService.new(project, current_user).execute(new_branch_name, 'master')
create(:protected_branch, name: new_branch_name, project: project)
expect do
@@ -629,7 +629,9 @@ describe API::Branches do
describe 'DELETE /projects/:id/repository/branches/:branch' do
before do
- allow_any_instance_of(Repository).to receive(:rm_branch).and_return(true)
+ allow_next_instance_of(Repository) do |instance|
+ allow(instance).to receive(:rm_branch).and_return(true)
+ end
end
it 'removes branch' do
@@ -666,7 +668,9 @@ describe API::Branches do
describe 'DELETE /projects/:id/repository/merged_branches' do
before do
- allow_any_instance_of(Repository).to receive(:rm_branch).and_return(true)
+ allow_next_instance_of(Repository) do |instance|
+ allow(instance).to receive(:rm_branch).and_return(true)
+ end
end
it 'returns 202 with json body' do
diff --git a/spec/requests/api/broadcast_messages_spec.rb b/spec/requests/api/broadcast_messages_spec.rb
index 541acb29857..9dc639a25a2 100644
--- a/spec/requests/api/broadcast_messages_spec.rb
+++ b/spec/requests/api/broadcast_messages_spec.rb
@@ -29,7 +29,7 @@ describe API::BroadcastMessages do
expect(response).to include_pagination_headers
expect(json_response).to be_kind_of(Array)
expect(json_response.first.keys)
- .to match_array(%w(id message starts_at ends_at color font active))
+ .to match_array(%w(id message starts_at ends_at color font active target_path))
end
end
@@ -52,7 +52,7 @@ describe API::BroadcastMessages do
expect(response).to have_gitlab_http_status(200)
expect(json_response['id']).to eq message.id
expect(json_response.keys)
- .to match_array(%w(id message starts_at ends_at color font active))
+ .to match_array(%w(id message starts_at ends_at color font active target_path))
end
end
@@ -100,6 +100,15 @@ describe API::BroadcastMessages do
expect(json_response['color']).to eq attrs[:color]
expect(json_response['font']).to eq attrs[:font]
end
+
+ it 'accepts a target path' do
+ attrs = attributes_for(:broadcast_message, target_path: "*/welcome")
+
+ post api('/broadcast_messages', admin), params: attrs
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['target_path']).to eq attrs[:target_path]
+ end
end
end
@@ -150,6 +159,15 @@ describe API::BroadcastMessages do
expect(response).to have_gitlab_http_status(200)
expect { message.reload }.to change { message.message }.to('new message')
end
+
+ it 'accepts a new target_path' do
+ attrs = { target_path: '*/welcome' }
+
+ put api("/broadcast_messages/#{message.id}", admin), params: attrs
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['target_path']).to eq attrs[:target_path]
+ end
end
end
diff --git a/spec/requests/api/deployments_spec.rb b/spec/requests/api/deployments_spec.rb
index 26849c0991d..3dc8e5749d4 100644
--- a/spec/requests/api/deployments_spec.rb
+++ b/spec/requests/api/deployments_spec.rb
@@ -30,40 +30,47 @@ describe API::Deployments do
expect(json_response.last['iid']).to eq(deployment_3.iid)
end
- describe 'ordering' do
- using RSpec::Parameterized::TableSyntax
+ context 'with updated_at filters specified' do
+ it 'returns projects deployments with last update in specified datetime range' do
+ get api("/projects/#{project.id}/deployments", user), params: { updated_before: 30.minutes.ago, updated_after: 90.minutes.ago }
- let(:order_by) { nil }
- let(:sort) { nil }
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response.first['id']).to eq(deployment_3.id)
+ end
+ end
+
+ describe 'ordering' do
+ let(:order_by) { 'iid' }
+ let(:sort) { 'desc' }
subject { get api("/projects/#{project.id}/deployments?order_by=#{order_by}&sort=#{sort}", user) }
+ before do
+ subject
+ end
+
def expect_deployments(ordered_deployments)
- json_response.each_with_index do |deployment_json, index|
- expect(deployment_json['id']).to eq(public_send(ordered_deployments[index]).id)
- end
+ expect(json_response.map { |d| d['id'] }).to eq(ordered_deployments.map(&:id))
end
- before do
- subject
+ it 'returns ordered deployments' do
+ expect(json_response.map { |i| i['id'] }).to eq([deployment_2.id, deployment_1.id, deployment_3.id])
end
- where(:order_by, :sort, :ordered_deployments) do
- 'created_at' | 'asc' | [:deployment_3, :deployment_2, :deployment_1]
- 'created_at' | 'desc' | [:deployment_1, :deployment_2, :deployment_3]
- 'id' | 'asc' | [:deployment_1, :deployment_2, :deployment_3]
- 'id' | 'desc' | [:deployment_3, :deployment_2, :deployment_1]
- 'iid' | 'asc' | [:deployment_3, :deployment_1, :deployment_2]
- 'iid' | 'desc' | [:deployment_2, :deployment_1, :deployment_3]
- 'ref' | 'asc' | [:deployment_2, :deployment_1, :deployment_3]
- 'ref' | 'desc' | [:deployment_3, :deployment_1, :deployment_2]
- 'updated_at' | 'asc' | [:deployment_2, :deployment_3, :deployment_1]
- 'updated_at' | 'desc' | [:deployment_1, :deployment_3, :deployment_2]
+ context 'with invalid order_by' do
+ let(:order_by) { 'wrong_sorting_value' }
+
+ it 'returns error' do
+ expect(response).to have_gitlab_http_status(400)
+ end
end
- with_them do
- it 'returns the deployments ordered' do
- expect_deployments(ordered_deployments)
+ context 'with invalid sorting' do
+ let(:sort) { 'wrong_sorting_direction' }
+
+ it 'returns error' do
+ expect(response).to have_gitlab_http_status(400)
end
end
end
@@ -140,7 +147,7 @@ describe API::Deployments do
expect(response).to have_gitlab_http_status(500)
end
- it 'links any merged merge requests to the deployment' do
+ it 'links any merged merge requests to the deployment', :sidekiq_inline do
mr = create(
:merge_request,
:merged,
@@ -192,7 +199,7 @@ describe API::Deployments do
expect(json_response['ref']).to eq('master')
end
- it 'links any merged merge requests to the deployment' do
+ it 'links any merged merge requests to the deployment', :sidekiq_inline do
mr = create(
:merge_request,
:merged,
@@ -335,4 +342,40 @@ describe API::Deployments do
end
end
end
+
+ context 'prevent N + 1 queries' do
+ context 'when the endpoint returns multiple records' do
+ let(:project) { create(:project) }
+
+ def create_record
+ create(:deployment, :success, project: project)
+ end
+
+ def request_with_query_count
+ ActiveRecord::QueryRecorder.new { trigger_request }.count
+ end
+
+ def trigger_request
+ get api("/projects/#{project.id}/deployments?order_by=updated_at&sort=asc", user)
+ end
+
+ before do
+ create_record
+ end
+
+ it 'succeeds' do
+ trigger_request
+
+ expect(response).to have_gitlab_http_status(200)
+
+ expect(json_response.size).to eq(1)
+ end
+
+ it 'does not increase the query count' do
+ expect { create_record }.not_to change { request_with_query_count }
+
+ expect(json_response.size).to eq(2)
+ end
+ end
+ end
end
diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb
index ec18156f49f..ab915af8ab0 100644
--- a/spec/requests/api/files_spec.rb
+++ b/spec/requests/api/files_spec.rb
@@ -315,11 +315,11 @@ describe API::Files do
expect(range['commit']['message'])
.to eq("Files, encoding and much more\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n")
- expect(range['commit']['authored_date']).to eq('2014-02-27T08:14:56.000Z')
+ expect(range['commit']['authored_date']).to eq('2014-02-27T10:14:56.000+02:00')
expect(range['commit']['author_name']).to eq('Dmitriy Zaporozhets')
expect(range['commit']['author_email']).to eq('dmitriy.zaporozhets@gmail.com')
- expect(range['commit']['committed_date']).to eq('2014-02-27T08:14:56.000Z')
+ expect(range['commit']['committed_date']).to eq('2014-02-27T10:14:56.000+02:00')
expect(range['commit']['committer_name']).to eq('Dmitriy Zaporozhets')
expect(range['commit']['committer_email']).to eq('dmitriy.zaporozhets@gmail.com')
end
@@ -548,8 +548,9 @@ describe API::Files do
end
it "returns a 400 if editor fails to create file" do
- allow_any_instance_of(Repository).to receive(:create_file)
- .and_raise(Gitlab::Git::CommitError, 'Cannot create file')
+ allow_next_instance_of(Repository) do |instance|
+ allow(instance).to receive(:create_file).and_raise(Gitlab::Git::CommitError, 'Cannot create file')
+ end
post api(route("any%2Etxt"), user), params: params
@@ -636,7 +637,7 @@ describe API::Files do
put api(route(file_path), user), params: params_with_stale_id
expect(response).to have_gitlab_http_status(400)
- expect(json_response['message']).to eq('You are attempting to update a file that has changed since you started editing it.')
+ expect(json_response['message']).to eq(_('You are attempting to update a file that has changed since you started editing it.'))
end
it "updates existing file in project repo with accepts correct last commit id" do
@@ -698,7 +699,9 @@ describe API::Files do
end
it "returns a 400 if fails to delete file" do
- allow_any_instance_of(Repository).to receive(:delete_file).and_raise(Gitlab::Git::CommitError, 'Cannot delete file')
+ allow_next_instance_of(Repository) do |instance|
+ allow(instance).to receive(:delete_file).and_raise(Gitlab::Git::CommitError, 'Cannot delete file')
+ end
delete api(route(file_path), user), params: params
diff --git a/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb b/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb
index 5b910d5bfe0..b24981873c8 100644
--- a/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb
+++ b/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb
@@ -75,6 +75,7 @@ describe 'Adding an AwardEmoji' do
describe 'marking Todos as done' do
let(:user) { current_user}
+
subject { post_graphql_mutation(mutation, current_user: user) }
include_examples 'creating award emojis marks Todos as done'
diff --git a/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb b/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
index ae628d3e56c..5e2c0e668a5 100644
--- a/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
+++ b/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
@@ -83,6 +83,7 @@ describe 'Toggling an AwardEmoji' do
describe 'marking Todos as done' do
let(:user) { current_user}
+
subject { post_graphql_mutation(mutation, current_user: user) }
include_examples 'creating award emojis marks Todos as done'
diff --git a/spec/requests/api/graphql/mutations/issues/set_confidential_spec.rb b/spec/requests/api/graphql/mutations/issues/set_confidential_spec.rb
new file mode 100644
index 00000000000..4d0bb59b030
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/issues/set_confidential_spec.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Setting an issue as confidential' do
+ include GraphqlHelpers
+
+ let(:current_user) { create(:user) }
+ let(:issue) { create(:issue) }
+ let(:project) { issue.project }
+ let(:input) { { confidential: true } }
+
+ let(:mutation) do
+ variables = {
+ project_path: project.full_path,
+ iid: issue.iid.to_s
+ }
+ graphql_mutation(:issue_set_confidential, variables.merge(input),
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ issue {
+ iid
+ confidential
+ }
+ QL
+ )
+ end
+
+ def mutation_response
+ graphql_mutation_response(:issue_set_confidential)
+ end
+
+ before do
+ project.add_developer(current_user)
+ end
+
+ it 'returns an error if the user is not allowed to update the issue' do
+ error = "The resource that you are attempting to access does not exist or you don't have permission to perform this action"
+ post_graphql_mutation(mutation, current_user: create(:user))
+
+ expect(graphql_errors).to include(a_hash_including('message' => error))
+ end
+
+ it 'updates the issue confidentiality' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['issue']['confidential']).to be_truthy
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/issues/set_due_date_spec.rb b/spec/requests/api/graphql/mutations/issues/set_due_date_spec.rb
new file mode 100644
index 00000000000..1efa9e16233
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/issues/set_due_date_spec.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Setting Due Date of an issue' do
+ include GraphqlHelpers
+
+ let(:current_user) { create(:user) }
+ let(:issue) { create(:issue) }
+ let(:project) { issue.project }
+ let(:input) { { due_date: 2.days.since } }
+
+ let(:mutation) do
+ variables = {
+ project_path: project.full_path,
+ iid: issue.iid.to_s
+ }
+ graphql_mutation(:issue_set_due_date, variables.merge(input),
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ issue {
+ iid
+ dueDate
+ }
+ QL
+ )
+ end
+
+ def mutation_response
+ graphql_mutation_response(:issue_set_due_date)
+ end
+
+ before do
+ project.add_developer(current_user)
+ end
+
+ it 'returns an error if the user is not allowed to update the issue' do
+ error = "The resource that you are attempting to access does not exist or you don't have permission to perform this action"
+ post_graphql_mutation(mutation, current_user: create(:user))
+
+ expect(graphql_errors).to include(a_hash_including('message' => error))
+ end
+
+ it 'updates the issue due date' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['issue']['dueDate']).to eq(2.days.since.to_date.to_s)
+ end
+
+ context 'when passing due date without a date value' do
+ let(:input) { { due_date: 'test' } }
+
+ it 'returns internal server error' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(graphql_errors).to include(a_hash_including('message' => 'Internal server error'))
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/snippets/create_spec.rb b/spec/requests/api/graphql/mutations/snippets/create_spec.rb
new file mode 100644
index 00000000000..9ef45c0f6bc
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/snippets/create_spec.rb
@@ -0,0 +1,144 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Creating a Snippet' do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let(:content) { 'Initial content' }
+ let(:description) { 'Initial description' }
+ let(:title) { 'Initial title' }
+ let(:file_name) { 'Initial file_name' }
+ let(:visibility_level) { 'public' }
+ let(:project_path) { nil }
+
+ let(:mutation) do
+ variables = {
+ content: content,
+ description: description,
+ visibility_level: visibility_level,
+ file_name: file_name,
+ title: title,
+ project_path: project_path
+ }
+
+ graphql_mutation(:create_snippet, variables)
+ end
+
+ def mutation_response
+ graphql_mutation_response(:create_snippet)
+ end
+
+ context 'when the user does not have permission' do
+ let(:current_user) { nil }
+
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+
+ it 'does not create the Snippet' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.not_to change { Snippet.count }
+ end
+
+ context 'when user is not authorized in the project' do
+ let(:project_path) { project.full_path }
+
+ it 'does not create the snippet when the user is not authorized' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.not_to change { Snippet.count }
+ end
+ end
+ end
+
+ context 'when the user has permission' do
+ let(:current_user) { user }
+
+ context 'with PersonalSnippet' do
+ it 'creates the Snippet' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to change { Snippet.count }.by(1)
+ end
+
+ it 'returns the created Snippet' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response['snippet']['content']).to eq(content)
+ expect(mutation_response['snippet']['title']).to eq(title)
+ expect(mutation_response['snippet']['description']).to eq(description)
+ expect(mutation_response['snippet']['fileName']).to eq(file_name)
+ expect(mutation_response['snippet']['visibilityLevel']).to eq(visibility_level)
+ expect(mutation_response['snippet']['project']).to be_nil
+ end
+ end
+
+ context 'with ProjectSnippet' do
+ let(:project_path) { project.full_path }
+
+ before do
+ project.add_developer(current_user)
+ end
+
+ it 'creates the Snippet' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to change { Snippet.count }.by(1)
+ end
+
+ it 'returns the created Snippet' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response['snippet']['content']).to eq(content)
+ expect(mutation_response['snippet']['title']).to eq(title)
+ expect(mutation_response['snippet']['description']).to eq(description)
+ expect(mutation_response['snippet']['fileName']).to eq(file_name)
+ expect(mutation_response['snippet']['visibilityLevel']).to eq(visibility_level)
+ expect(mutation_response['snippet']['project']['fullPath']).to eq(project_path)
+ end
+
+ context 'when the project path is invalid' do
+ let(:project_path) { 'foobar' }
+
+ it 'returns an an error' do
+ post_graphql_mutation(mutation, current_user: current_user)
+ errors = json_response['errors']
+
+ expect(errors.first['message']).to eq(Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR)
+ end
+ end
+
+ context 'when the feature is disabled' do
+ it 'returns an an error' do
+ project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::DISABLED)
+
+ post_graphql_mutation(mutation, current_user: current_user)
+ errors = json_response['errors']
+
+ expect(errors.first['message']).to eq(Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR)
+ end
+ end
+ end
+
+ context 'when there are ActiveRecord validation errors' do
+ let(:title) { '' }
+
+ it_behaves_like 'a mutation that returns errors in the response', errors: ["Title can't be blank"]
+
+ it 'does not create the Snippet' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.not_to change { Snippet.count }
+ end
+
+ it 'does not return Snippet' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response['snippet']).to be_nil
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/snippets/destroy_spec.rb b/spec/requests/api/graphql/mutations/snippets/destroy_spec.rb
new file mode 100644
index 00000000000..351d2db8973
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/snippets/destroy_spec.rb
@@ -0,0 +1,89 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Destroying a Snippet' do
+ include GraphqlHelpers
+
+ let(:current_user) { snippet.author }
+ let(:mutation) do
+ variables = {
+ id: snippet.to_global_id.to_s
+ }
+
+ graphql_mutation(:destroy_snippet, variables)
+ end
+
+ def mutation_response
+ graphql_mutation_response(:destroy_snippet)
+ end
+
+ shared_examples 'graphql delete actions' do
+ context 'when the user does not have permission' do
+ let(:current_user) { create(:user) }
+
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+
+ it 'does not destroy the Snippet' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.not_to change { Snippet.count }
+ end
+ end
+
+ context 'when the user has permission' do
+ it 'destroys the Snippet' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to change { Snippet.count }.by(-1)
+ end
+
+ it 'returns an empty Snippet' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response).to have_key('snippet')
+ expect(mutation_response['snippet']).to be_nil
+ end
+ end
+ end
+
+ describe 'PersonalSnippet' do
+ it_behaves_like 'graphql delete actions' do
+ let_it_be(:snippet) { create(:personal_snippet) }
+ end
+ end
+
+ describe 'ProjectSnippet' do
+ let_it_be(:project) { create(:project, :private) }
+ let_it_be(:snippet) { create(:project_snippet, :private, project: project, author: create(:user)) }
+
+ context 'when the author is not a member of the project' do
+ it 'returns an an error' do
+ post_graphql_mutation(mutation, current_user: current_user)
+ errors = json_response['errors']
+
+ expect(errors.first['message']).to eq(Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR)
+ end
+ end
+
+ context 'when the author is a member of the project' do
+ before do
+ project.add_developer(current_user)
+ end
+
+ it_behaves_like 'graphql delete actions'
+
+ context 'when the snippet project feature is disabled' do
+ it 'returns an an error' do
+ project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::DISABLED)
+
+ post_graphql_mutation(mutation, current_user: current_user)
+ errors = json_response['errors']
+
+ expect(errors.first['message']).to eq(Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb b/spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb
new file mode 100644
index 00000000000..0e8fe4987b9
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Mark snippet as spam' do
+ include GraphqlHelpers
+
+ let_it_be(:admin) { create(:admin) }
+ let_it_be(:other_user) { create(:user) }
+ let_it_be(:snippet) { create(:personal_snippet) }
+ let_it_be(:user_agent_detail) { create(:user_agent_detail, subject: snippet) }
+ let(:current_user) { snippet.author }
+ let(:mutation) do
+ variables = {
+ id: snippet.to_global_id.to_s
+ }
+
+ graphql_mutation(:mark_as_spam_snippet, variables)
+ end
+
+ def mutation_response
+ graphql_mutation_response(:mark_as_spam_snippet)
+ end
+
+ shared_examples 'does not mark the snippet as spam' do
+ it do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.not_to change { snippet.reload.user_agent_detail.submitted }
+ end
+ end
+
+ context 'when the user does not have permission' do
+ let(:current_user) { other_user }
+
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+
+ it_behaves_like 'does not mark the snippet as spam'
+ end
+
+ context 'when the user has permission' do
+ context 'when user can not mark snippet as spam' do
+ it_behaves_like 'does not mark the snippet as spam'
+ end
+
+ context 'when user can mark snippet as spam' do
+ let(:current_user) { admin }
+
+ before do
+ stub_application_setting(akismet_enabled: true)
+ end
+
+ it 'marks snippet as spam' do
+ expect_next_instance_of(SpamService) do |instance|
+ expect(instance).to receive(:mark_as_spam!)
+ end
+
+ post_graphql_mutation(mutation, current_user: current_user)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/snippets/update_spec.rb b/spec/requests/api/graphql/mutations/snippets/update_spec.rb
new file mode 100644
index 00000000000..deaa9e8a237
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/snippets/update_spec.rb
@@ -0,0 +1,144 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Updating a Snippet' do
+ include GraphqlHelpers
+
+ let_it_be(:original_content) { 'Initial content' }
+ let_it_be(:original_description) { 'Initial description' }
+ let_it_be(:original_title) { 'Initial title' }
+ let_it_be(:original_file_name) { 'Initial file_name' }
+ let(:updated_content) { 'Updated content' }
+ let(:updated_description) { 'Updated description' }
+ let(:updated_title) { 'Updated_title' }
+ let(:updated_file_name) { 'Updated file_name' }
+ let(:current_user) { snippet.author }
+
+ let(:mutation) do
+ variables = {
+ id: GitlabSchema.id_from_object(snippet).to_s,
+ content: updated_content,
+ description: updated_description,
+ visibility_level: 'public',
+ file_name: updated_file_name,
+ title: updated_title
+ }
+
+ graphql_mutation(:update_snippet, variables)
+ end
+
+ def mutation_response
+ graphql_mutation_response(:update_snippet)
+ end
+
+ shared_examples 'graphql update actions' do
+ context 'when the user does not have permission' do
+ let(:current_user) { create(:user) }
+
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+
+ it 'does not update the Snippet' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.not_to change { snippet.reload }
+ end
+ end
+
+ context 'when the user has permission' do
+ it 'updates the Snippet' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(snippet.reload.title).to eq(updated_title)
+ end
+
+ it 'returns the updated Snippet' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response['snippet']['content']).to eq(updated_content)
+ expect(mutation_response['snippet']['title']).to eq(updated_title)
+ expect(mutation_response['snippet']['description']).to eq(updated_description)
+ expect(mutation_response['snippet']['fileName']).to eq(updated_file_name)
+ expect(mutation_response['snippet']['visibilityLevel']).to eq('public')
+ end
+
+ context 'when there are ActiveRecord validation errors' do
+ let(:updated_title) { '' }
+
+ it_behaves_like 'a mutation that returns errors in the response', errors: ["Title can't be blank"]
+
+ it 'does not update the Snippet' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(snippet.reload.title).to eq(original_title)
+ end
+
+ it 'returns the Snippet with its original values' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response['snippet']['content']).to eq(original_content)
+ expect(mutation_response['snippet']['title']).to eq(original_title)
+ expect(mutation_response['snippet']['description']).to eq(original_description)
+ expect(mutation_response['snippet']['fileName']).to eq(original_file_name)
+ expect(mutation_response['snippet']['visibilityLevel']).to eq('private')
+ end
+ end
+ end
+ end
+
+ describe 'PersonalSnippet' do
+ it_behaves_like 'graphql update actions' do
+ let_it_be(:snippet) do
+ create(:personal_snippet,
+ :private,
+ file_name: original_file_name,
+ title: original_title,
+ content: original_content,
+ description: original_description)
+ end
+ end
+ end
+
+ describe 'ProjectSnippet' do
+ let_it_be(:project) { create(:project, :private) }
+ let_it_be(:snippet) do
+ create(:project_snippet,
+ :private,
+ project: project,
+ author: create(:user),
+ file_name: original_file_name,
+ title: original_title,
+ content: original_content,
+ description: original_description)
+ end
+
+ context 'when the author is not a member of the project' do
+ it 'returns an an error' do
+ post_graphql_mutation(mutation, current_user: current_user)
+ errors = json_response['errors']
+
+ expect(errors.first['message']).to eq(Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR)
+ end
+ end
+
+ context 'when the author is a member of the project' do
+ before do
+ project.add_developer(current_user)
+ end
+
+ it_behaves_like 'graphql update actions'
+
+ context 'when the snippet project feature is disabled' do
+ it 'returns an an error' do
+ project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::DISABLED)
+
+ post_graphql_mutation(mutation, current_user: current_user)
+ errors = json_response['errors']
+
+ expect(errors.first['message']).to eq(Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb b/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb
new file mode 100644
index 00000000000..40e085027d7
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Marking all todos done' do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:author) { create(:user) }
+ let_it_be(:other_user) { create(:user) }
+ let_it_be(:other_user2) { create(:user) }
+
+ let_it_be(:todo1) { create(:todo, user: current_user, author: author, state: :pending) }
+ let_it_be(:todo2) { create(:todo, user: current_user, author: author, state: :done) }
+ let_it_be(:todo3) { create(:todo, user: current_user, author: author, state: :pending) }
+
+ let_it_be(:other_user_todo) { create(:todo, user: other_user, author: author, state: :pending) }
+
+ let(:input) { {} }
+
+ let(:mutation) do
+ graphql_mutation(:todos_mark_all_done, input,
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ updatedIds
+ QL
+ )
+ end
+
+ def mutation_response
+ graphql_mutation_response(:todos_mark_all_done)
+ end
+
+ it 'marks all pending todos as done' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(todo1.reload.state).to eq('done')
+ expect(todo2.reload.state).to eq('done')
+ expect(todo3.reload.state).to eq('done')
+ expect(other_user_todo.reload.state).to eq('pending')
+
+ updated_todo_ids = mutation_response['updatedIds']
+ expect(updated_todo_ids).to contain_exactly(global_id_of(todo1), global_id_of(todo3))
+ end
+
+ it 'behaves as expected if there are no todos for the requesting user' do
+ post_graphql_mutation(mutation, current_user: other_user2)
+
+ expect(todo1.reload.state).to eq('pending')
+ expect(todo2.reload.state).to eq('done')
+ expect(todo3.reload.state).to eq('pending')
+ expect(other_user_todo.reload.state).to eq('pending')
+
+ updated_todo_ids = mutation_response['updatedIds']
+ expect(updated_todo_ids).to be_empty
+ end
+
+ context 'when user is not logged in' do
+ let(:current_user) { nil }
+
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: ['The resource that you are attempting to access does not exist or you don\'t have permission to perform this action']
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/todos/restore_spec.rb b/spec/requests/api/graphql/mutations/todos/restore_spec.rb
new file mode 100644
index 00000000000..faa36c8273a
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/todos/restore_spec.rb
@@ -0,0 +1,97 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Restoring Todos' do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:author) { create(:user) }
+ let_it_be(:other_user) { create(:user) }
+
+ let_it_be(:todo1) { create(:todo, user: current_user, author: author, state: :done) }
+ let_it_be(:todo2) { create(:todo, user: current_user, author: author, state: :pending) }
+
+ let_it_be(:other_user_todo) { create(:todo, user: other_user, author: author, state: :done) }
+
+ let(:input) { { id: todo1.to_global_id.to_s } }
+
+ let(:mutation) do
+ graphql_mutation(:todo_restore, input,
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ todo {
+ id
+ state
+ }
+ QL
+ )
+ end
+
+ def mutation_response
+ graphql_mutation_response(:todo_restore)
+ end
+
+ it 'restores a single todo' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(todo1.reload.state).to eq('pending')
+ expect(todo2.reload.state).to eq('pending')
+ expect(other_user_todo.reload.state).to eq('done')
+
+ todo = mutation_response['todo']
+ expect(todo['id']).to eq(todo1.to_global_id.to_s)
+ expect(todo['state']).to eq('pending')
+ end
+
+ context 'when todo is already marked pending' do
+ let(:input) { { id: todo2.to_global_id.to_s } }
+
+ it 'has the expected response' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(todo1.reload.state).to eq('done')
+ expect(todo2.reload.state).to eq('pending')
+ expect(other_user_todo.reload.state).to eq('done')
+
+ todo = mutation_response['todo']
+ expect(todo['id']).to eq(todo2.to_global_id.to_s)
+ expect(todo['state']).to eq('pending')
+ end
+ end
+
+ context 'when todo does not belong to requesting user' do
+ let(:input) { { id: other_user_todo.to_global_id.to_s } }
+ let(:access_error) { 'The resource that you are attempting to access does not exist or you don\'t have permission to perform this action' }
+
+ it 'contains the expected error' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ errors = json_response['errors']
+ expect(errors).not_to be_blank
+ expect(errors.first['message']).to eq(access_error)
+
+ expect(todo1.reload.state).to eq('done')
+ expect(todo2.reload.state).to eq('pending')
+ expect(other_user_todo.reload.state).to eq('done')
+ end
+ end
+
+ context 'when using an invalid gid' do
+ let(:input) { { id: 'invalid_gid' } }
+ let(:invalid_gid_error) { 'invalid_gid is not a valid GitLab id.' }
+
+ it 'contains the expected error' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ errors = json_response['errors']
+ expect(errors).not_to be_blank
+ expect(errors.first['message']).to eq(invalid_gid_error)
+
+ expect(todo1.reload.state).to eq('done')
+ expect(todo2.reload.state).to eq('pending')
+ expect(other_user_todo.reload.state).to eq('done')
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/project/error_tracking/sentry_detailed_error_request_spec.rb b/spec/requests/api/graphql/project/error_tracking/sentry_detailed_error_request_spec.rb
new file mode 100644
index 00000000000..d10380dab3a
--- /dev/null
+++ b/spec/requests/api/graphql/project/error_tracking/sentry_detailed_error_request_spec.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+describe 'getting a detailed sentry error' do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:project_setting) { create(:project_error_tracking_setting, project: project) }
+ let_it_be(:current_user) { project.owner }
+ let_it_be(:sentry_detailed_error) { build(:detailed_error_tracking_error) }
+ let(:sentry_gid) { sentry_detailed_error.to_global_id.to_s }
+ let(:fields) do
+ <<~QUERY
+ #{all_graphql_fields_for('SentryDetailedError'.classify)}
+ QUERY
+ end
+
+ let(:query) do
+ graphql_query_for(
+ 'project',
+ { 'fullPath' => project.full_path },
+ query_graphql_field('sentryDetailedError', { id: sentry_gid }, fields)
+ )
+ end
+
+ let(:error_data) { graphql_data['project']['sentryDetailedError'] }
+
+ it_behaves_like 'a working graphql query' do
+ before do
+ post_graphql(query, current_user: current_user)
+ end
+ end
+
+ context 'when data is loading via reactive cache' do
+ before do
+ post_graphql(query, current_user: current_user)
+ end
+
+ it "is expected to return an empty error" do
+ expect(error_data).to eq nil
+ end
+ end
+
+ context 'reactive cache returns data' do
+ before do
+ expect_any_instance_of(ErrorTracking::ProjectErrorTrackingSetting)
+ .to receive(:issue_details)
+ .and_return({ issue: sentry_detailed_error })
+
+ post_graphql(query, current_user: current_user)
+ end
+
+ it "is expected to return a valid error" do
+ expect(error_data['id']).to eql sentry_gid
+ expect(error_data['sentryId']).to eql sentry_detailed_error.id.to_s
+ expect(error_data['status']).to eql sentry_detailed_error.status.upcase
+ expect(error_data['firstSeen']).to eql sentry_detailed_error.first_seen
+ expect(error_data['lastSeen']).to eql sentry_detailed_error.last_seen
+ end
+
+ it 'is expected to return the frequency correctly' do
+ expect(error_data['frequency'].count).to eql sentry_detailed_error.frequency.count
+
+ first_frequency = error_data['frequency'].first
+ expect(Time.parse(first_frequency['time'])).to eql Time.at(sentry_detailed_error.frequency[0][0], in: 0)
+ expect(first_frequency['count']).to eql sentry_detailed_error.frequency[0][1]
+ end
+ end
+end
diff --git a/spec/requests/api/graphql_spec.rb b/spec/requests/api/graphql_spec.rb
index 54401ec4085..d0378278600 100644
--- a/spec/requests/api/graphql_spec.rb
+++ b/spec/requests/api/graphql_spec.rb
@@ -46,7 +46,7 @@ describe 'GraphQL' do
end
it 'logs the exception in Sentry and continues with the request' do
- expect(Gitlab::Sentry).to receive(:track_exception).at_least(1).times
+ expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception).at_least(1).times
expect(Gitlab::GraphqlLogger).to receive(:info)
post_graphql(query, variables: {})
@@ -146,7 +146,7 @@ describe 'GraphQL' do
end
it "logs a warning that the 'calls_gitaly' field declaration is missing" do
- expect(Gitlab::Sentry).to receive(:track_exception).once
+ expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception).once
post_graphql(query, current_user: user)
end
diff --git a/spec/requests/api/group_clusters_spec.rb b/spec/requests/api/group_clusters_spec.rb
index 97465647a87..14027db01c4 100644
--- a/spec/requests/api/group_clusters_spec.rb
+++ b/spec/requests/api/group_clusters_spec.rb
@@ -261,7 +261,7 @@ describe API::GroupClusters do
it 'responds with 400' do
expect(response).to have_gitlab_http_status(400)
- expect(json_response['message']['base'].first).to include('Instance does not support multiple Kubernetes clusters')
+ expect(json_response['message']['base'].first).to eq(_('Instance does not support multiple Kubernetes clusters'))
end
end
@@ -372,7 +372,7 @@ describe API::GroupClusters do
end
it 'returns validation error' do
- expect(json_response['message']['platform_kubernetes.base'].first).to eq('Cannot modify managed Kubernetes cluster')
+ expect(json_response['message']['platform_kubernetes.base'].first).to eq(_('Cannot modify managed Kubernetes cluster'))
end
end
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index cb97398805a..a4f68df928f 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -488,6 +488,51 @@ describe API::Groups do
expect(response).to have_gitlab_http_status(404)
end
end
+
+ context 'limiting the number of projects and shared_projects in the response' do
+ let(:limit) { 1 }
+
+ before do
+ stub_const("GroupProjectsFinder::DEFAULT_PROJECTS_LIMIT", limit)
+
+ # creates 3 public projects
+ create_list(:project, 3, :public, namespace: group1)
+
+ # creates 3 shared projects
+ public_group = create(:group, :public)
+ projects_to_be_shared = create_list(:project, 3, :public, namespace: public_group)
+
+ projects_to_be_shared.each do |project|
+ create(:project_group_link, project: project, group: group1)
+ end
+ end
+
+ context 'when limiting feature is enabled' do
+ before do
+ stub_feature_flags(limit_projects_in_groups_api: true)
+ end
+
+ it 'limits projects and shared_projects' do
+ get api("/groups/#{group1.id}")
+
+ expect(json_response['projects'].count).to eq(limit)
+ expect(json_response['shared_projects'].count).to eq(limit)
+ end
+ end
+
+ context 'when limiting feature is not enabled' do
+ before do
+ stub_feature_flags(limit_projects_in_groups_api: false)
+ end
+
+ it 'does not limit projects and shared_projects' do
+ get api("/groups/#{group1.id}")
+
+ expect(json_response['projects'].count).to eq(3)
+ expect(json_response['shared_projects'].count).to eq(3)
+ end
+ end
+ end
end
describe 'PUT /groups/:id' do
@@ -1030,8 +1075,9 @@ describe API::Groups do
let(:project_path) { CGI.escape(project.full_path) }
before do
- allow_any_instance_of(Projects::TransferService)
- .to receive(:execute).and_return(true)
+ allow_next_instance_of(Projects::TransferService) do |instance|
+ allow(instance).to receive(:execute).and_return(true)
+ end
end
context "when authenticated as user" do
diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb
index bbfe40041a1..26174611c58 100644
--- a/spec/requests/api/helpers_spec.rb
+++ b/spec/requests/api/helpers_spec.rb
@@ -146,13 +146,13 @@ describe API::Helpers do
let(:personal_access_token) { create(:personal_access_token, user: user) }
it "returns a 401 response for an invalid token" do
- env[Gitlab::Auth::UserAuthFinders::PRIVATE_TOKEN_HEADER] = 'invalid token'
+ env[Gitlab::Auth::AuthFinders::PRIVATE_TOKEN_HEADER] = 'invalid token'
expect { current_user }.to raise_error /401/
end
it "returns a 403 response for a user without access" do
- env[Gitlab::Auth::UserAuthFinders::PRIVATE_TOKEN_HEADER] = personal_access_token.token
+ env[Gitlab::Auth::AuthFinders::PRIVATE_TOKEN_HEADER] = personal_access_token.token
allow_any_instance_of(Gitlab::UserAccess).to receive(:allowed?).and_return(false)
expect { current_user }.to raise_error /403/
@@ -160,7 +160,7 @@ describe API::Helpers do
it 'returns a 403 response for a user who is blocked' do
user.block!
- env[Gitlab::Auth::UserAuthFinders::PRIVATE_TOKEN_HEADER] = personal_access_token.token
+ env[Gitlab::Auth::AuthFinders::PRIVATE_TOKEN_HEADER] = personal_access_token.token
expect { current_user }.to raise_error /403/
end
@@ -168,7 +168,7 @@ describe API::Helpers do
context 'when terms are enforced' do
before do
enforce_terms
- env[Gitlab::Auth::UserAuthFinders::PRIVATE_TOKEN_HEADER] = personal_access_token.token
+ env[Gitlab::Auth::AuthFinders::PRIVATE_TOKEN_HEADER] = personal_access_token.token
end
it 'returns a 403 when a user has not accepted the terms' do
@@ -183,27 +183,27 @@ describe API::Helpers do
end
it "sets current_user" do
- env[Gitlab::Auth::UserAuthFinders::PRIVATE_TOKEN_HEADER] = personal_access_token.token
+ env[Gitlab::Auth::AuthFinders::PRIVATE_TOKEN_HEADER] = personal_access_token.token
expect(current_user).to eq(user)
end
it "does not allow tokens without the appropriate scope" do
personal_access_token = create(:personal_access_token, user: user, scopes: ['read_user'])
- env[Gitlab::Auth::UserAuthFinders::PRIVATE_TOKEN_HEADER] = personal_access_token.token
+ env[Gitlab::Auth::AuthFinders::PRIVATE_TOKEN_HEADER] = personal_access_token.token
expect { current_user }.to raise_error Gitlab::Auth::InsufficientScopeError
end
it 'does not allow revoked tokens' do
personal_access_token.revoke!
- env[Gitlab::Auth::UserAuthFinders::PRIVATE_TOKEN_HEADER] = personal_access_token.token
+ env[Gitlab::Auth::AuthFinders::PRIVATE_TOKEN_HEADER] = personal_access_token.token
expect { current_user }.to raise_error Gitlab::Auth::RevokedError
end
it 'does not allow expired tokens' do
personal_access_token.update!(expires_at: 1.day.ago)
- env[Gitlab::Auth::UserAuthFinders::PRIVATE_TOKEN_HEADER] = personal_access_token.token
+ env[Gitlab::Auth::AuthFinders::PRIVATE_TOKEN_HEADER] = personal_access_token.token
expect { current_user }.to raise_error Gitlab::Auth::ExpiredError
end
@@ -213,7 +213,7 @@ describe API::Helpers do
before do
stub_config_setting(impersonation_enabled: false)
- env[Gitlab::Auth::UserAuthFinders::PRIVATE_TOKEN_HEADER] = personal_access_token.token
+ env[Gitlab::Auth::AuthFinders::PRIVATE_TOKEN_HEADER] = personal_access_token.token
end
it 'does not allow impersonation tokens' do
@@ -226,11 +226,11 @@ describe API::Helpers do
describe '.handle_api_exception' do
before do
allow_any_instance_of(self.class).to receive(:rack_response)
- allow(Gitlab::Sentry).to receive(:enabled?).and_return(true)
stub_sentry_settings
- configure_sentry
+ expect(Gitlab::ErrorTracking).to receive(:sentry_dsn).and_return(Gitlab.config.sentry.dsn)
+ Gitlab::ErrorTracking.configure
Raven.client.configuration.encoding = 'json'
end
@@ -478,7 +478,7 @@ describe API::Helpers do
context 'passed as param' do
before do
- set_param(Gitlab::Auth::UserAuthFinders::PRIVATE_TOKEN_PARAM, token.token)
+ set_param(Gitlab::Auth::AuthFinders::PRIVATE_TOKEN_PARAM, token.token)
end
it_behaves_like 'sudo'
@@ -486,7 +486,7 @@ describe API::Helpers do
context 'passed as header' do
before do
- env[Gitlab::Auth::UserAuthFinders::PRIVATE_TOKEN_HEADER] = token.token
+ env[Gitlab::Auth::AuthFinders::PRIVATE_TOKEN_HEADER] = token.token
end
it_behaves_like 'sudo'
diff --git a/spec/requests/api/internal/base_spec.rb b/spec/requests/api/internal/base_spec.rb
index fcff2cde730..ecbb81294a0 100644
--- a/spec/requests/api/internal/base_spec.rb
+++ b/spec/requests/api/internal/base_spec.rb
@@ -193,7 +193,15 @@ describe API::Internal::Base do
end
it 'responds successfully when a user is not found' do
- get(api("/internal/discover"), params: { username: 'noone', secret_token: secret_token })
+ get(api('/internal/discover'), params: { username: 'noone', secret_token: secret_token })
+
+ expect(response).to have_gitlab_http_status(200)
+
+ expect(response.body).to eq('null')
+ end
+
+ it 'response successfully when passing invalid params' do
+ get(api('/internal/discover'), params: { nothing: 'to find a user', secret_token: secret_token })
expect(response).to have_gitlab_http_status(200)
@@ -318,7 +326,7 @@ describe API::Internal::Base do
expect(json_response["gitaly"]["repository"]["relative_path"]).to eq(project.repository.gitaly_repository.relative_path)
expect(json_response["gitaly"]["address"]).to eq(Gitlab::GitalyClient.address(project.repository_storage))
expect(json_response["gitaly"]["token"]).to eq(Gitlab::GitalyClient.token(project.repository_storage))
- expect(json_response["gitaly"]["features"]).to eq('gitaly-feature-get-all-lfs-pointers-go' => 'true', 'gitaly-feature-inforef-uploadpack-cache' => 'true')
+ expect(json_response["gitaly"]["features"]).to eq('gitaly-feature-inforef-uploadpack-cache' => 'true', 'gitaly-feature-get-tag-messages-go' => 'true', 'gitaly-feature-filter-shas-with-signatures-go' => 'true')
expect(user.reload.last_activity_on).to eql(Date.today)
end
end
@@ -338,7 +346,7 @@ describe API::Internal::Base do
expect(json_response["gitaly"]["repository"]["relative_path"]).to eq(project.repository.gitaly_repository.relative_path)
expect(json_response["gitaly"]["address"]).to eq(Gitlab::GitalyClient.address(project.repository_storage))
expect(json_response["gitaly"]["token"]).to eq(Gitlab::GitalyClient.token(project.repository_storage))
- expect(json_response["gitaly"]["features"]).to eq('gitaly-feature-get-all-lfs-pointers-go' => 'true', 'gitaly-feature-inforef-uploadpack-cache' => 'true')
+ expect(json_response["gitaly"]["features"]).to eq('gitaly-feature-inforef-uploadpack-cache' => 'true', 'gitaly-feature-get-tag-messages-go' => 'true', 'gitaly-feature-filter-shas-with-signatures-go' => 'true')
expect(user.reload.last_activity_on).to be_nil
end
end
@@ -580,7 +588,7 @@ describe API::Internal::Base do
expect(json_response["gitaly"]["repository"]["relative_path"]).to eq(project.repository.gitaly_repository.relative_path)
expect(json_response["gitaly"]["address"]).to eq(Gitlab::GitalyClient.address(project.repository_storage))
expect(json_response["gitaly"]["token"]).to eq(Gitlab::GitalyClient.token(project.repository_storage))
- expect(json_response["gitaly"]["features"]).to eq('gitaly-feature-get-all-lfs-pointers-go' => 'true', 'gitaly-feature-inforef-uploadpack-cache' => 'true')
+ expect(json_response["gitaly"]["features"]).to eq('gitaly-feature-inforef-uploadpack-cache' => 'true', 'gitaly-feature-get-tag-messages-go' => 'true', 'gitaly-feature-filter-shas-with-signatures-go' => 'true')
end
end
@@ -819,7 +827,6 @@ describe API::Internal::Base do
before do
project.add_developer(user)
- allow(described_class).to receive(:identify).and_return(user)
allow_any_instance_of(Gitlab::Identifier).to receive(:identify).and_return(user)
end
diff --git a/spec/requests/api/internal/pages_spec.rb b/spec/requests/api/internal/pages_spec.rb
index 03bf748b471..2887163fe58 100644
--- a/spec/requests/api/internal/pages_spec.rb
+++ b/spec/requests/api/internal/pages_spec.rb
@@ -4,10 +4,10 @@ require 'spec_helper'
describe API::Internal::Pages do
describe "GET /internal/pages" do
- let(:pages_shared_secret) { SecureRandom.random_bytes(Gitlab::Pages::SECRET_LENGTH) }
+ let(:pages_secret) { SecureRandom.random_bytes(Gitlab::Pages::SECRET_LENGTH) }
before do
- allow(Gitlab::Pages).to receive(:secret).and_return(pages_shared_secret)
+ allow(Gitlab::Pages).to receive(:secret).and_return(pages_secret)
end
def query_host(host, headers = {})
@@ -47,11 +47,12 @@ describe API::Internal::Pages do
project.mark_pages_as_deployed
end
- context 'not existing host' do
- it 'responds with 404 Not Found' do
+ context 'domain does not exist' do
+ it 'responds with 204 no content' do
query_host('pages.gitlab.io')
- expect(response).to have_gitlab_http_status(404)
+ expect(response).to have_gitlab_http_status(204)
+ expect(response.body).to be_empty
end
end
diff --git a/spec/requests/api/issues/get_project_issues_spec.rb b/spec/requests/api/issues/get_project_issues_spec.rb
index 06a43ea6b02..59aeb91edd2 100644
--- a/spec/requests/api/issues/get_project_issues_spec.rb
+++ b/spec/requests/api/issues/get_project_issues_spec.rb
@@ -589,6 +589,24 @@ describe API::Issues do
expect(json_response['subscribed']).to be_truthy
end
+ context "moved_to_id" do
+ let(:moved_issue) do
+ create(:closed_issue, project: project, moved_to: issue)
+ end
+
+ it 'returns null when not moved' do
+ get api("/projects/#{project.id}/issues/#{issue.iid}", user)
+
+ expect(json_response['moved_to_id']).to be_nil
+ end
+
+ it 'returns issue id when moved' do
+ get api("/projects/#{project.id}/issues/#{moved_issue.iid}", user)
+
+ expect(json_response['moved_to_id']).to eq(issue.id)
+ end
+ end
+
it 'exposes the closed_at attribute' do
get api("/projects/#{project.id}/issues/#{closed_issue.iid}", user)
diff --git a/spec/requests/api/issues/issues_spec.rb b/spec/requests/api/issues/issues_spec.rb
index 61a94b682be..50a0a80b542 100644
--- a/spec/requests/api/issues/issues_spec.rb
+++ b/spec/requests/api/issues/issues_spec.rb
@@ -832,7 +832,7 @@ describe API::Issues do
end
context 'when issue does not exist' do
- it 'returns 404 when trying to move an issue' do
+ it 'returns 404 when trying to delete an issue' do
delete api("/projects/#{project.id}/issues/123", user)
expect(response).to have_gitlab_http_status(404)
diff --git a/spec/requests/api/issues/post_projects_issues_spec.rb b/spec/requests/api/issues/post_projects_issues_spec.rb
index 3a55b437ead..e9f678d164e 100644
--- a/spec/requests/api/issues/post_projects_issues_spec.rb
+++ b/spec/requests/api/issues/post_projects_issues_spec.rb
@@ -453,7 +453,7 @@ describe API::Issues do
params: { to_project_id: project.id }
expect(response).to have_gitlab_http_status(400)
- expect(json_response['message']).to eq('Cannot move issue to project it originates from!')
+ expect(json_response['message']).to eq(s_('MoveIssue|Cannot move issue to project it originates from!'))
end
end
@@ -463,7 +463,7 @@ describe API::Issues do
params: { to_project_id: target_project2.id }
expect(response).to have_gitlab_http_status(400)
- expect(json_response['message']).to eq('Cannot move issue due to insufficient permissions!')
+ expect(json_response['message']).to eq(s_('MoveIssue|Cannot move issue due to insufficient permissions!'))
end
end
diff --git a/spec/requests/api/jobs_spec.rb b/spec/requests/api/jobs_spec.rb
index 020e7659a4c..82bf607b911 100644
--- a/spec/requests/api/jobs_spec.rb
+++ b/spec/requests/api/jobs_spec.rb
@@ -795,9 +795,11 @@ describe API::Jobs do
before do
stub_remote_url_206(url, file_path)
- allow_any_instance_of(JobArtifactUploader).to receive(:file_storage?) { false }
- allow_any_instance_of(JobArtifactUploader).to receive(:url) { url }
- allow_any_instance_of(JobArtifactUploader).to receive(:size) { File.size(file_path) }
+ allow_next_instance_of(JobArtifactUploader) do |instance|
+ allow(instance).to receive(:file_storage?) { false }
+ allow(instance).to receive(:url) { url }
+ allow(instance).to receive(:size) { File.size(file_path) }
+ end
end
it 'returns specific job trace' do
diff --git a/spec/requests/api/keys_spec.rb b/spec/requests/api/keys_spec.rb
index 6802a0cfdab..f7da1abcfdf 100644
--- a/spec/requests/api/keys_spec.rb
+++ b/spec/requests/api/keys_spec.rb
@@ -25,7 +25,6 @@ describe API::Keys do
it 'returns single ssh key with user information' do
user.keys << key
- user.save
get api("/keys/#{key.id}", admin)
expect(response).to have_gitlab_http_status(200)
expect(json_response['title']).to eq(key.title)
@@ -40,4 +39,73 @@ describe API::Keys do
end
end
end
+
+ describe 'GET /keys?fingerprint=' do
+ it 'returns authentication error' do
+ get api("/keys?fingerprint=#{key.fingerprint}")
+
+ expect(response).to have_gitlab_http_status(401)
+ end
+
+ it 'returns authentication error when authenticated as user' do
+ get api("/keys?fingerprint=#{key.fingerprint}", user)
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+
+ context 'when authenticated as admin' do
+ it 'returns 404 for non-existing SSH md5 fingerprint' do
+ get api("/keys?fingerprint=11:11:11:11:11:11:11:11:11:11:11:11:11:11:11:11", admin)
+
+ expect(response).to have_gitlab_http_status(404)
+ expect(json_response['message']).to eq('404 Key Not Found')
+ end
+
+ it 'returns 404 for non-existing SSH sha256 fingerprint' do
+ get api("/keys?fingerprint=#{URI.encode_www_form_component("SHA256:nUhzNyftwADy8AH3wFY31tAKs7HufskYTte2aXo1lCg")}", admin)
+
+ expect(response).to have_gitlab_http_status(404)
+ expect(json_response['message']).to eq('404 Key Not Found')
+ end
+
+ it 'returns user if SSH md5 fingerprint found' do
+ user.keys << key
+
+ get api("/keys?fingerprint=#{key.fingerprint}", admin)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['title']).to eq(key.title)
+ expect(json_response['user']['id']).to eq(user.id)
+ expect(json_response['user']['username']).to eq(user.username)
+ end
+
+ it 'returns user if SSH sha256 fingerprint found' do
+ user.keys << key
+
+ get api("/keys?fingerprint=#{URI.encode_www_form_component("SHA256:" + key.fingerprint_sha256)}", admin)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['title']).to eq(key.title)
+ expect(json_response['user']['id']).to eq(user.id)
+ expect(json_response['user']['username']).to eq(user.username)
+ end
+
+ it 'returns user if SSH sha256 fingerprint found' do
+ user.keys << key
+
+ get api("/keys?fingerprint=#{URI.encode_www_form_component("sha256:" + key.fingerprint_sha256)}", admin)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['title']).to eq(key.title)
+ expect(json_response['user']['id']).to eq(user.id)
+ expect(json_response['user']['username']).to eq(user.username)
+ end
+
+ it "does not include the user's `is_admin` flag" do
+ get api("/keys?fingerprint=#{key.fingerprint}", admin)
+
+ expect(json_response['user']['is_admin']).to be_nil
+ end
+ end
+ end
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index c96c80b6998..e5ad1a6378e 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -1567,6 +1567,18 @@ describe API::MergeRequests do
expect(response).to have_gitlab_http_status(200)
end
+ it 'does not merge if merge_when_pipeline_succeeds is passed and the pipeline has failed' do
+ create(:ci_pipeline,
+ :failed,
+ sha: merge_request.diff_head_sha,
+ merge_requests_as_head_pipeline: [merge_request])
+
+ put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user), params: { merge_when_pipeline_succeeds: true }
+
+ expect(response).to have_gitlab_http_status(405)
+ expect(merge_request.reload.state).to eq('opened')
+ end
+
it "enables merge when pipeline succeeds if the pipeline is active" do
allow_any_instance_of(MergeRequest).to receive_messages(head_pipeline: pipeline, actual_head_pipeline: pipeline)
allow(pipeline).to receive(:active?).and_return(true)
diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb
index e57d7699892..cc2038a7245 100644
--- a/spec/requests/api/notes_spec.rb
+++ b/spec/requests/api/notes_spec.rb
@@ -92,7 +92,7 @@ describe API::Notes do
end
context "current user can view the note" do
- it "returns an empty array" do
+ it "returns a non-empty array" do
get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes", private_user)
expect(response).to have_gitlab_http_status(200)
diff --git a/spec/requests/api/pages/pages_spec.rb b/spec/requests/api/pages/pages_spec.rb
new file mode 100644
index 00000000000..2085c509eff
--- /dev/null
+++ b/spec/requests/api/pages/pages_spec.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe API::Pages do
+ let_it_be(:project) { create(:project, path: 'my.project', pages_https_only: false) }
+ let_it_be(:admin) { create(:admin) }
+ let_it_be(:user) { create(:user) }
+
+ before do
+ project.add_maintainer(user)
+ project.mark_pages_as_deployed
+ end
+
+ describe 'DELETE /projects/:id/pages' do
+ context 'when Pages is disabled' do
+ before do
+ allow(Gitlab.config.pages).to receive(:enabled).and_return(false)
+ end
+
+ it_behaves_like '404 response' do
+ let(:request) { delete api("/projects/#{project.id}/pages", admin)}
+ end
+ end
+
+ context 'when Pages is enabled' do
+ before do
+ allow(Gitlab.config.pages).to receive(:enabled).and_return(true)
+ end
+
+ context 'when Pages are deployed' do
+ it 'returns 204' do
+ delete api("/projects/#{project.id}/pages", admin)
+
+ expect(response).to have_gitlab_http_status(204)
+ end
+
+ it 'removes the pages' do
+ expect_any_instance_of(Gitlab::PagesTransfer).to receive(:rename_project).and_return true
+ expect(PagesWorker).to receive(:perform_in).with(5.minutes, :remove, project.namespace.full_path, anything)
+
+ delete api("/projects/#{project.id}/pages", admin )
+
+ expect(project.reload.pages_metadatum.deployed?).to be(false)
+ end
+ end
+
+ context 'when pages are not deployed' do
+ before do
+ project.mark_pages_as_not_deployed
+ end
+
+ it 'returns 204' do
+ delete api("/projects/#{project.id}/pages", admin)
+
+ expect(response).to have_gitlab_http_status(204)
+ end
+ end
+
+ context 'when there is no project' do
+ it 'returns 404' do
+ id = -1
+
+ delete api("/projects/#{id}/pages", admin)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/pipelines_spec.rb b/spec/requests/api/pipelines_spec.rb
index cce52cfc1ca..a9d570b5696 100644
--- a/spec/requests/api/pipelines_spec.rb
+++ b/spec/requests/api/pipelines_spec.rb
@@ -237,6 +237,20 @@ describe API::Pipelines do
end
end
+ context 'when updated_at filters are specified' do
+ let!(:pipeline1) { create(:ci_pipeline, project: project, updated_at: 2.days.ago) }
+ let!(:pipeline2) { create(:ci_pipeline, project: project, updated_at: 4.days.ago) }
+ let!(:pipeline3) { create(:ci_pipeline, project: project, updated_at: 1.hour.ago) }
+
+ it 'returns pipelines with last update date in specified datetime range' do
+ get api("/projects/#{project.id}/pipelines", user), params: { updated_before: 1.day.ago, updated_after: 3.days.ago }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response.first['id']).to eq(pipeline1.id)
+ end
+ end
+
context 'when order_by and sort are specified' do
context 'when order_by user_id' do
before do
@@ -384,7 +398,7 @@ describe API::Pipelines do
post api("/projects/#{project.id}/pipeline", user), params: { ref: project.default_branch }
expect(response).to have_gitlab_http_status(400)
- expect(json_response['message']['base'].first).to eq 'Missing .gitlab-ci.yml file'
+ expect(json_response['message']['base'].first).to eq 'Missing CI config file'
expect(json_response).not_to be_an Array
end
end
diff --git a/spec/requests/api/project_clusters_spec.rb b/spec/requests/api/project_clusters_spec.rb
index 04e59238877..f3d005322f2 100644
--- a/spec/requests/api/project_clusters_spec.rb
+++ b/spec/requests/api/project_clusters_spec.rb
@@ -260,7 +260,7 @@ describe API::ProjectClusters do
it 'responds with 400' do
expect(response).to have_gitlab_http_status(400)
- expect(json_response['message']['base'].first).to eq('Instance does not support multiple Kubernetes clusters')
+ expect(json_response['message']['base'].first).to eq(_('Instance does not support multiple Kubernetes clusters'))
end
end
@@ -376,7 +376,7 @@ describe API::ProjectClusters do
end
it 'returns validation error' do
- expect(json_response['message']['platform_kubernetes.base'].first).to eq('Cannot modify managed Kubernetes cluster')
+ expect(json_response['message']['platform_kubernetes.base'].first).to eq(_('Cannot modify managed Kubernetes cluster'))
end
end
diff --git a/spec/requests/api/project_export_spec.rb b/spec/requests/api/project_export_spec.rb
index 605ff888234..37f2cc85a50 100644
--- a/spec/requests/api/project_export_spec.rb
+++ b/spec/requests/api/project_export_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe API::ProjectExport do
+describe API::ProjectExport, :clean_gitlab_redis_cache do
set(:project) { create(:project) }
set(:project_none) { create(:project) }
set(:project_started) { create(:project) }
@@ -47,6 +47,19 @@ describe API::ProjectExport do
it_behaves_like '404 response'
end
+ shared_examples_for 'when rate limit is exceeded' do
+ before do
+ allow(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true)
+ end
+
+ it 'prevents requesting project export' do
+ request
+
+ expect(response).to have_gitlab_http_status(429)
+ expect(json_response['message']['error']).to eq('This endpoint has been requested too many times. Try again later.')
+ end
+ end
+
describe 'GET /projects/:project_id/export' do
shared_examples_for 'get project export status not found' do
it_behaves_like '404 response' do
@@ -219,6 +232,12 @@ describe API::ProjectExport do
let(:user) { admin }
it_behaves_like 'get project download by strategy'
+
+ context 'when rate limit is exceeded' do
+ let(:request) { get api(download_path, admin) }
+
+ include_examples 'when rate limit is exceeded'
+ end
end
context 'when user is a maintainer' do
@@ -329,6 +348,12 @@ describe API::ProjectExport do
let(:user) { admin }
it_behaves_like 'post project export start'
+
+ context 'when rate limit is exceeded' do
+ let(:request) { post api(path, admin) }
+
+ include_examples 'when rate limit is exceeded'
+ end
end
context 'when user is a maintainer' do
diff --git a/spec/requests/api/project_import_spec.rb b/spec/requests/api/project_import_spec.rb
index 866adbd424e..186f0f52a46 100644
--- a/spec/requests/api/project_import_spec.rb
+++ b/spec/requests/api/project_import_spec.rb
@@ -7,6 +7,7 @@ describe API::ProjectImport do
let(:user) { create(:user) }
let(:file) { File.join('spec', 'features', 'projects', 'import_export', 'test_project_export.tar.gz') }
let(:namespace) { create(:group) }
+
before do
allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
stub_uploads_object_storage(FileUploader)
diff --git a/spec/requests/api/project_snippets_spec.rb b/spec/requests/api/project_snippets_spec.rb
index cac3f07d0d0..bfb6f10efa3 100644
--- a/spec/requests/api/project_snippets_spec.rb
+++ b/spec/requests/api/project_snippets_spec.rb
@@ -179,7 +179,9 @@ describe API::ProjectSnippets do
end
before do
- allow_any_instance_of(AkismetService).to receive(:spam?).and_return(true)
+ allow_next_instance_of(AkismetService) do |instance|
+ allow(instance).to receive(:spam?).and_return(true)
+ end
end
context 'when the snippet is private' do
@@ -269,7 +271,9 @@ describe API::ProjectSnippets do
end
before do
- allow_any_instance_of(AkismetService).to receive(:spam?).and_return(true)
+ allow_next_instance_of(AkismetService) do |instance|
+ allow(instance).to receive(:spam?).and_return(true)
+ end
end
context 'when the snippet is private' do
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index cda2dd7d2f4..9af4f484f99 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -1882,6 +1882,7 @@ describe API::Projects do
describe "POST /projects/:id/share" do
let(:group) { create(:group) }
+
before do
group.add_developer(user)
end
diff --git a/spec/requests/api/releases_spec.rb b/spec/requests/api/releases_spec.rb
index bf05587fe03..da04e852795 100644
--- a/spec/requests/api/releases_spec.rb
+++ b/spec/requests/api/releases_spec.rb
@@ -558,6 +558,43 @@ describe API::Releases do
end
end
+ context 'when using JOB-TOKEN auth' do
+ let(:job) { create(:ci_build, user: maintainer) }
+ let(:params) do
+ {
+ name: 'Another release',
+ tag_name: 'v0.2',
+ description: 'Another nice release',
+ released_at: '2019-04-25T10:00:00+09:00'
+ }
+ end
+
+ context 'when no token is provided' do
+ it 'returns a :not_found error' do
+ post api("/projects/#{project.id}/releases"), params: params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when an invalid token is provided' do
+ it 'returns an :unauthorized error' do
+ post api("/projects/#{project.id}/releases"), params: params.merge(job_token: 'yadayadayada')
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
+
+ context 'when a valid token is provided' do
+ it 'creates the release' do
+ post api("/projects/#{project.id}/releases"), params: params.merge(job_token: job.token)
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(project.releases.last.description).to eq('Another nice release')
+ end
+ end
+ end
+
context 'when tag does not exist in git repository' do
let(:params) do
{
diff --git a/spec/requests/api/remote_mirrors_spec.rb b/spec/requests/api/remote_mirrors_spec.rb
new file mode 100644
index 00000000000..c5ba9bd223e
--- /dev/null
+++ b/spec/requests/api/remote_mirrors_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe API::RemoteMirrors do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :repository, :remote_mirror) }
+
+ describe 'GET /projects/:id/remote_mirrors' do
+ let(:route) { "/projects/#{project.id}/remote_mirrors" }
+
+ it 'requires `admin_remote_mirror` permission' do
+ project.add_developer(user)
+
+ get api(route, user)
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+
+ it 'returns a list of remote mirrors' do
+ project.add_maintainer(user)
+
+ get api(route, user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(response).to match_response_schema('remote_mirrors')
+ end
+
+ context 'with the `remote_mirrors_api` feature disabled' do
+ before do
+ stub_feature_flags(remote_mirrors_api: false)
+ end
+
+ it 'responds with `not_found`' do
+ get api(route, user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb
index 6138036b0af..cc6cadb190a 100644
--- a/spec/requests/api/runner_spec.rb
+++ b/spec/requests/api/runner_spec.rb
@@ -513,6 +513,16 @@ describe API::Runner, :clean_gitlab_redis_shared_state do
expect(json_response['features']).to eq(expected_features)
end
+ it 'creates persistent ref' do
+ expect_any_instance_of(Ci::PersistentRef).to receive(:create_ref)
+ .with(job.sha, "refs/#{Repository::REF_PIPELINES}/#{job.commit_id}")
+
+ request_job info: { platform: :darwin }
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['id']).to eq(job.id)
+ end
+
context 'when job is made for tag' do
let!(:job) { create(:ci_build, :tag, pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0) }
diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb
index a080b59173f..7c7620389b4 100644
--- a/spec/requests/api/services_spec.rb
+++ b/spec/requests/api/services_spec.rb
@@ -4,7 +4,6 @@ require "spec_helper"
describe API::Services do
set(:user) { create(:user) }
- set(:admin) { create(:admin) }
set(:user2) { create(:user) }
set(:project) do
@@ -88,14 +87,7 @@ describe API::Services do
expect(response).to have_gitlab_http_status(401)
end
- it "returns all properties of service #{service} when authenticated as admin" do
- get api("/projects/#{project.id}/services/#{dashed_service}", admin)
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response['properties'].keys).to match_array(service_instance.api_field_names)
- end
-
- it "returns properties of service #{service} other than passwords when authenticated as project owner" do
+ it "returns all properties of service #{service}" do
get api("/projects/#{project.id}/services/#{dashed_service}", user)
expect(response).to have_gitlab_http_status(200)
diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb
index b7586307929..af86ba86303 100644
--- a/spec/requests/api/settings_spec.rb
+++ b/spec/requests/api/settings_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
describe API::Settings, 'Settings' do
let(:user) { create(:user) }
+
set(:admin) { create(:admin) }
describe "GET /application/settings" do
@@ -36,6 +37,7 @@ describe API::Settings, 'Settings' do
expect(json_response['allow_local_requests_from_system_hooks']).to be(true)
expect(json_response).not_to have_key('performance_bar_allowed_group_path')
expect(json_response).not_to have_key('performance_bar_enabled')
+ expect(json_response['snippet_size_limit']).to eq(50.megabytes)
end
end
@@ -85,7 +87,8 @@ describe API::Settings, 'Settings' do
allow_local_requests_from_web_hooks_and_services: true,
allow_local_requests_from_system_hooks: false,
push_event_hooks_limit: 2,
- push_event_activities_limit: 2
+ push_event_activities_limit: 2,
+ snippet_size_limit: 5
}
expect(response).to have_gitlab_http_status(200)
@@ -121,6 +124,7 @@ describe API::Settings, 'Settings' do
expect(json_response['allow_local_requests_from_system_hooks']).to eq(false)
expect(json_response['push_event_hooks_limit']).to eq(2)
expect(json_response['push_event_activities_limit']).to eq(2)
+ expect(json_response['snippet_size_limit']).to eq(5)
end
end
diff --git a/spec/requests/api/snippets_spec.rb b/spec/requests/api/snippets_spec.rb
index 36d2a0d7ea7..f32be7a8765 100644
--- a/spec/requests/api/snippets_spec.rb
+++ b/spec/requests/api/snippets_spec.rb
@@ -66,6 +66,9 @@ describe API::Snippets do
let!(:public_snippet_other) { create(:personal_snippet, :public, author: other_user) }
let!(:private_snippet_other) { create(:personal_snippet, :private, author: other_user) }
let!(:internal_snippet_other) { create(:personal_snippet, :internal, author: other_user) }
+ let!(:public_snippet_project) { create(:project_snippet, :public, author: user) }
+ let!(:private_snippet_project) { create(:project_snippet, :private, author: user) }
+ let!(:internal_snippet_project) { create(:project_snippet, :internal, author: user) }
it 'returns all snippets with public visibility from all users' do
get api("/snippets/public", user)
@@ -76,10 +79,10 @@ describe API::Snippets do
expect(json_response.map { |snippet| snippet['id']} ).to contain_exactly(
public_snippet.id,
public_snippet_other.id)
- expect(json_response.map { |snippet| snippet['web_url']} ).to include(
+ expect(json_response.map { |snippet| snippet['web_url']} ).to contain_exactly(
"http://localhost/snippets/#{public_snippet.id}",
"http://localhost/snippets/#{public_snippet_other.id}")
- expect(json_response.map { |snippet| snippet['raw_url']} ).to include(
+ expect(json_response.map { |snippet| snippet['raw_url']} ).to contain_exactly(
"http://localhost/snippets/#{public_snippet.id}/raw",
"http://localhost/snippets/#{public_snippet_other.id}/raw")
end
@@ -235,7 +238,9 @@ describe API::Snippets do
end
before do
- allow_any_instance_of(AkismetService).to receive(:spam?).and_return(true)
+ allow_next_instance_of(AkismetService) do |instance|
+ allow(instance).to receive(:spam?).and_return(true)
+ end
end
context 'when the snippet is private' do
@@ -322,7 +327,9 @@ describe API::Snippets do
end
before do
- allow_any_instance_of(AkismetService).to receive(:spam?).and_return(true)
+ allow_next_instance_of(AkismetService) do |instance|
+ allow(instance).to receive(:spam?).and_return(true)
+ end
end
context 'when the snippet is private' do
@@ -368,6 +375,7 @@ describe API::Snippets do
describe 'DELETE /snippets/:id' do
let!(:public_snippet) { create(:personal_snippet, :public, author: user) }
+
it 'deletes snippet' do
expect do
delete api("/snippets/#{public_snippet.id}", user)
diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb
index dca87d5e4ce..09e63b86cfc 100644
--- a/spec/requests/api/tags_spec.rb
+++ b/spec/requests/api/tags_spec.rb
@@ -328,7 +328,9 @@ describe API::Tags do
let(:route) { "/projects/#{project_id}/repository/tags/#{tag_name}" }
before do
- allow_any_instance_of(Repository).to receive(:rm_tag).and_return(true)
+ allow_next_instance_of(Repository) do |instance|
+ allow(instance).to receive(:rm_tag).and_return(true)
+ end
end
shared_examples_for 'repository delete tag' do
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 1a1e80f1ce3..0a22a09b8a6 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -1261,6 +1261,25 @@ describe API::Users do
expect { Namespace.find(namespace.id) }.to raise_error ActiveRecord::RecordNotFound
end
+ context "sole owner of a group" do
+ let!(:group) { create(:group).tap { |group| group.add_owner(user) } }
+
+ context "hard delete disabled" do
+ it "does not delete user" do
+ perform_enqueued_jobs { delete api("/users/#{user.id}", admin)}
+ expect(response).to have_gitlab_http_status(409)
+ end
+ end
+
+ context "hard delete enabled" do
+ it "delete user and group", :sidekiq_might_not_need_inline do
+ perform_enqueued_jobs { delete api("/users/#{user.id}?hard_delete=true", admin)}
+ expect(response).to have_gitlab_http_status(204)
+ expect(Group.exists?(group.id)).to be_falsy
+ end
+ end
+ end
+
it_behaves_like '412 response' do
let(:request) { api("/users/#{user.id}", admin) }
end
@@ -2105,6 +2124,7 @@ describe API::Users do
describe 'GET /user/status' do
let(:path) { '/user/status' }
+
it_behaves_like 'rendering user status'
end
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb
index 1b17d492b0c..42b4bd71b88 100644
--- a/spec/requests/git_http_spec.rb
+++ b/spec/requests/git_http_spec.rb
@@ -456,7 +456,7 @@ describe 'Git HTTP requests' do
end
it "responds with status 403" do
- expect(Rack::Attack::Allow2Ban).to receive(:filter).and_return(true)
+ expect(Rack::Attack::Allow2Ban).to receive(:banned?).and_return(true)
expect(Gitlab::AuthLogger).to receive(:error).with({
message: 'Rack_Attack',
env: :blocklist,
diff --git a/spec/requests/jwt_controller_spec.rb b/spec/requests/jwt_controller_spec.rb
index c1f99115612..199c2dbe9ca 100644
--- a/spec/requests/jwt_controller_spec.rb
+++ b/spec/requests/jwt_controller_spec.rb
@@ -134,7 +134,9 @@ describe JwtController do
context 'when internal auth is disabled' do
it 'rejects the authorization attempt with personal access token message' do
- allow_any_instance_of(ApplicationSetting).to receive(:password_authentication_enabled_for_git?) { false }
+ allow_next_instance_of(ApplicationSetting) do |instance|
+ allow(instance).to receive(:password_authentication_enabled_for_git?) { false }
+ end
get '/jwt/auth', params: parameters, headers: headers
expect(response).to have_gitlab_http_status(401)
diff --git a/spec/requests/projects/merge_requests/creations_spec.rb b/spec/requests/projects/merge_requests/creations_spec.rb
new file mode 100644
index 00000000000..d192e1bca7f
--- /dev/null
+++ b/spec/requests/projects/merge_requests/creations_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'merge requests creations' do
+ describe 'GET /:namespace/:project/merge_requests/new' do
+ include ProjectForksHelper
+
+ let(:project) { create(:project, :repository) }
+ let(:user) { project.owner }
+
+ before do
+ login_as(user)
+ end
+
+ def get_new
+ get namespace_project_new_merge_request_path(namespace_id: project.namespace, project_id: project)
+ end
+
+ it 'avoids N+1 DB queries even with forked projects' do
+ control = ActiveRecord::QueryRecorder.new(skip_cached: false) { get_new }
+
+ 5.times { fork_project(project, user) }
+
+ expect { get_new }.not_to exceed_query_limit(control)
+ end
+ end
+end
diff --git a/spec/requests/rack_attack_global_spec.rb b/spec/requests/rack_attack_global_spec.rb
index 4d5055a7e27..9968b2e4aba 100644
--- a/spec/requests/rack_attack_global_spec.rb
+++ b/spec/requests/rack_attack_global_spec.rb
@@ -84,7 +84,9 @@ describe 'Rack Attack global throttles' do
expect(response).to have_http_status 200
end
- expect_any_instance_of(Rack::Attack::Request).to receive(:ip).at_least(:once).and_return('1.2.3.4')
+ expect_next_instance_of(Rack::Attack::Request) do |instance|
+ expect(instance).to receive(:ip).at_least(:once).and_return('1.2.3.4')
+ end
# would be over limit for the same IP
get url_that_does_not_require_authentication
@@ -100,6 +102,18 @@ describe 'Rack Attack global throttles' do
end
end
+ context 'when the request is authenticated by a runner token' do
+ let(:request_jobs_url) { '/api/v4/jobs/request' }
+ let(:runner) { create(:ci_runner) }
+
+ it 'does not cont as unauthenticated' do
+ (1 + requests_per_period).times do
+ post request_jobs_url, params: { token: runner.token }
+ expect(response).to have_http_status 204
+ end
+ end
+ end
+
it 'logs RackAttack info into structured logs' do
requests_per_period.times do
get url_that_does_not_require_authentication
@@ -249,10 +263,10 @@ describe 'Rack Attack global throttles' do
expect_rejection { post protected_path_that_does_not_require_authentication, params: post_params }
end
- context 'when Omnibus throttle is present' do
+ context 'when Omnibus throttle should be used' do
before do
allow(Gitlab::Throttle)
- .to receive(:omnibus_protected_paths_present?).and_return(true)
+ .to receive(:should_use_omnibus_protected_paths?).and_return(true)
end
it 'allows requests over the rate limit' do
@@ -298,7 +312,7 @@ describe 'Rack Attack global throttles' do
it_behaves_like 'rate-limited token-authenticated requests'
end
- context 'when Omnibus throttle is present' do
+ context 'when Omnibus throttle should be used' do
let(:request_args) { [api(api_partial_url, personal_access_token: token)] }
let(:other_user_request_args) { [api(api_partial_url, personal_access_token: other_user_token)] }
@@ -309,7 +323,7 @@ describe 'Rack Attack global throttles' do
stub_application_setting(settings_to_set)
allow(Gitlab::Throttle)
- .to receive(:omnibus_protected_paths_present?).and_return(true)
+ .to receive(:should_use_omnibus_protected_paths?).and_return(true)
end
it 'allows requests over the rate limit' do
@@ -339,7 +353,7 @@ describe 'Rack Attack global throttles' do
it_behaves_like 'rate-limited web authenticated requests'
- context 'when Omnibus throttle is present' do
+ context 'when Omnibus throttle should be used' do
before do
settings_to_set[:"#{throttle_setting_prefix}_requests_per_period"] = requests_per_period
settings_to_set[:"#{throttle_setting_prefix}_period_in_seconds"] = period_in_seconds
@@ -347,7 +361,7 @@ describe 'Rack Attack global throttles' do
stub_application_setting(settings_to_set)
allow(Gitlab::Throttle)
- .to receive(:omnibus_protected_paths_present?).and_return(true)
+ .to receive(:should_use_omnibus_protected_paths?).and_return(true)
login_as(user)
end
diff --git a/spec/requests/user_avatar_spec.rb b/spec/requests/user_avatar_spec.rb
new file mode 100644
index 00000000000..9451674161c
--- /dev/null
+++ b/spec/requests/user_avatar_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Loading a user avatar' do
+ let(:user) { create(:user, :with_avatar) }
+
+ context 'when logged in' do
+ # The exact query count will vary depending on the 2FA settings of the
+ # instance, group, and user. Removing those extra 2FA queries in this case
+ # may not be a good idea, so we just set up the ideal case.
+ before do
+ stub_application_setting(require_two_factor_authentication: true)
+
+ login_as(create(:user, :two_factor))
+ end
+
+ # One each for: current user, avatar user, and upload record
+ it 'only performs three SQL queries' do
+ get user.avatar_url # Skip queries on first application load
+
+ expect(response).to have_gitlab_http_status(200)
+ expect { get user.avatar_url }.not_to exceed_query_limit(3)
+ end
+ end
+
+ context 'when logged out' do
+ # One each for avatar user and upload record
+ it 'only performs two SQL queries' do
+ get user.avatar_url # Skip queries on first application load
+
+ expect(response).to have_gitlab_http_status(200)
+ expect { get user.avatar_url }.not_to exceed_query_limit(2)
+ end
+ end
+end