summaryrefslogtreecommitdiff
path: root/spec/requests
diff options
context:
space:
mode:
Diffstat (limited to 'spec/requests')
-rw-r--r--spec/requests/api/branches_spec.rb16
-rw-r--r--spec/requests/api/builds_spec.rb14
-rw-r--r--spec/requests/api/commits_spec.rb20
-rw-r--r--spec/requests/api/files_spec.rb8
-rw-r--r--spec/requests/api/groups_spec.rb6
-rw-r--r--spec/requests/api/issues_spec.rb51
-rw-r--r--spec/requests/api/labels_spec.rb34
-rw-r--r--spec/requests/api/merge_requests_spec.rb24
-rw-r--r--spec/requests/api/project_snippets_spec.rb92
-rw-r--r--spec/requests/api/projects_spec.rb51
-rw-r--r--spec/requests/api/snippets_spec.rb66
-rw-r--r--spec/requests/api/templates_spec.rb8
-rw-r--r--spec/requests/api/todos_spec.rb27
-rw-r--r--spec/requests/api/v3/commits_spec.rb578
-rw-r--r--spec/requests/api/v3/files_spec.rb270
-rw-r--r--spec/requests/api/v3/issues_spec.rb29
-rw-r--r--spec/requests/api/v3/labels_spec.rb92
-rw-r--r--spec/requests/api/v3/merge_requests_spec.rb2
-rw-r--r--spec/requests/api/v3/notes_spec.rb432
-rw-r--r--spec/requests/api/v3/project_snippets_spec.rb92
-rw-r--r--spec/requests/api/v3/projects_spec.rb2
-rw-r--r--spec/requests/api/v3/templates_spec.rb8
-rw-r--r--spec/requests/api/v3/todos_spec.rb73
-rw-r--r--spec/requests/api/v3/users_spec.rb77
-rw-r--r--spec/requests/ci/api/builds_spec.rb2
-rw-r--r--spec/requests/ci/api/runners_spec.rb2
-rw-r--r--spec/requests/ci/api/triggers_spec.rb3
-rw-r--r--spec/requests/lfs_http_spec.rb178
28 files changed, 2022 insertions, 235 deletions
diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb
index 2e6db0f43c6..5571f6cc107 100644
--- a/spec/requests/api/branches_spec.rb
+++ b/spec/requests/api/branches_spec.rb
@@ -272,7 +272,7 @@ describe API::Branches, api: true do
describe "POST /projects/:id/repository/branches" do
it "creates a new branch" do
post api("/projects/#{project.id}/repository/branches", user),
- branch_name: 'feature1',
+ branch: 'feature1',
ref: branch_sha
expect(response).to have_http_status(201)
@@ -283,14 +283,14 @@ describe API::Branches, api: true do
it "denies for user without push access" do
post api("/projects/#{project.id}/repository/branches", user2),
- branch_name: branch_name,
+ branch: branch_name,
ref: branch_sha
expect(response).to have_http_status(403)
end
it 'returns 400 if branch name is invalid' do
post api("/projects/#{project.id}/repository/branches", user),
- branch_name: 'new design',
+ branch: 'new design',
ref: branch_sha
expect(response).to have_http_status(400)
expect(json_response['message']).to eq('Branch name is invalid')
@@ -298,12 +298,12 @@ describe API::Branches, api: true do
it 'returns 400 if branch already exists' do
post api("/projects/#{project.id}/repository/branches", user),
- branch_name: 'new_design1',
+ branch: 'new_design1',
ref: branch_sha
expect(response).to have_http_status(201)
post api("/projects/#{project.id}/repository/branches", user),
- branch_name: 'new_design1',
+ branch: 'new_design1',
ref: branch_sha
expect(response).to have_http_status(400)
expect(json_response['message']).to eq('Branch already exists')
@@ -311,7 +311,7 @@ describe API::Branches, api: true do
it 'returns 400 if ref name is invalid' do
post api("/projects/#{project.id}/repository/branches", user),
- branch_name: 'new_design3',
+ branch: 'new_design3',
ref: 'foo'
expect(response).to have_http_status(400)
expect(json_response['message']).to eq('Invalid reference name')
@@ -326,14 +326,14 @@ describe API::Branches, api: true do
it "removes branch" do
delete api("/projects/#{project.id}/repository/branches/#{branch_name}", user)
expect(response).to have_http_status(200)
- expect(json_response['branch_name']).to eq(branch_name)
+ expect(json_response['branch']).to eq(branch_name)
end
it "removes a branch with dots in the branch name" do
delete api("/projects/#{project.id}/repository/branches/with.1.2.3", user)
expect(response).to have_http_status(200)
- expect(json_response['branch_name']).to eq("with.1.2.3")
+ expect(json_response['branch']).to eq("with.1.2.3")
end
it 'returns 404 if branch not exists' do
diff --git a/spec/requests/api/builds_spec.rb b/spec/requests/api/builds_spec.rb
index 38aef7f2767..76a10a2374c 100644
--- a/spec/requests/api/builds_spec.rb
+++ b/spec/requests/api/builds_spec.rb
@@ -16,6 +16,8 @@ describe API::Builds, api: true do
let(:query) { '' }
before do
+ create(:ci_build, :skipped, pipeline: pipeline)
+
get api("/projects/#{project.id}/builds?#{query}", api_user)
end
@@ -49,6 +51,18 @@ describe API::Builds, api: true do
end
end
+ context 'filter project with scope skipped' do
+ let(:query) { 'scope=skipped' }
+ let(:json_build) { json_response.first }
+
+ it 'return builds with status skipped' do
+ expect(response).to have_http_status 200
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq 1
+ expect(json_build['status']).to eq 'skipped'
+ end
+ end
+
context 'filter project with array of scope elements' do
let(:query) { 'scope[0]=pending&scope[1]=running' }
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index ecc6a597869..8b3dfedc5a9 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -107,7 +107,7 @@ describe API::Commits, api: true do
let(:message) { 'Created file' }
let!(:invalid_c_params) do
{
- branch_name: 'master',
+ branch: 'master',
commit_message: message,
actions: [
{
@@ -120,7 +120,7 @@ describe API::Commits, api: true do
end
let!(:valid_c_params) do
{
- branch_name: 'master',
+ branch: 'master',
commit_message: message,
actions: [
{
@@ -162,7 +162,7 @@ describe API::Commits, api: true do
let(:message) { 'Deleted file' }
let!(:invalid_d_params) do
{
- branch_name: 'markdown',
+ branch: 'markdown',
commit_message: message,
actions: [
{
@@ -174,7 +174,7 @@ describe API::Commits, api: true do
end
let!(:valid_d_params) do
{
- branch_name: 'markdown',
+ branch: 'markdown',
commit_message: message,
actions: [
{
@@ -203,7 +203,7 @@ describe API::Commits, api: true do
let(:message) { 'Moved file' }
let!(:invalid_m_params) do
{
- branch_name: 'feature',
+ branch: 'feature',
commit_message: message,
actions: [
{
@@ -217,7 +217,7 @@ describe API::Commits, api: true do
end
let!(:valid_m_params) do
{
- branch_name: 'feature',
+ branch: 'feature',
commit_message: message,
actions: [
{
@@ -248,7 +248,7 @@ describe API::Commits, api: true do
let(:message) { 'Updated file' }
let!(:invalid_u_params) do
{
- branch_name: 'master',
+ branch: 'master',
commit_message: message,
actions: [
{
@@ -261,7 +261,7 @@ describe API::Commits, api: true do
end
let!(:valid_u_params) do
{
- branch_name: 'master',
+ branch: 'master',
commit_message: message,
actions: [
{
@@ -291,7 +291,7 @@ describe API::Commits, api: true do
let(:message) { 'Multiple actions' }
let!(:invalid_mo_params) do
{
- branch_name: 'master',
+ branch: 'master',
commit_message: message,
actions: [
{
@@ -319,7 +319,7 @@ describe API::Commits, api: true do
end
let!(:valid_mo_params) do
{
- branch_name: 'master',
+ branch: 'master',
commit_message: message,
actions: [
{
diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb
index 5e26e779366..a8ce0430401 100644
--- a/spec/requests/api/files_spec.rb
+++ b/spec/requests/api/files_spec.rb
@@ -104,7 +104,7 @@ describe API::Files, api: true do
let(:valid_params) do
{
file_path: 'newfile.rb',
- branch_name: 'master',
+ branch: 'master',
content: 'puts 8',
commit_message: 'Added newfile'
}
@@ -153,7 +153,7 @@ describe API::Files, api: true do
let(:valid_params) do
{
file_path: file_path,
- branch_name: 'master',
+ branch: 'master',
content: 'puts 8',
commit_message: 'Changed file'
}
@@ -193,7 +193,7 @@ describe API::Files, api: true do
let(:valid_params) do
{
file_path: file_path,
- branch_name: 'master',
+ branch: 'master',
commit_message: 'Changed file'
}
end
@@ -241,7 +241,7 @@ describe API::Files, api: true do
let(:put_params) do
{
file_path: file_path,
- branch_name: 'master',
+ branch: 'master',
content: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=',
commit_message: 'Binary file with a \n should not be touched',
encoding: 'base64'
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index a59112579e5..9c3a92bedbd 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -303,7 +303,7 @@ describe API::Groups, api: true do
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
expect(json_response.length).to eq(2)
- project_names = json_response.map { |proj| proj['name' ] }
+ project_names = json_response.map { |proj| proj['name'] }
expect(project_names).to match_array([project1.name, project3.name])
expect(json_response.first['visibility_level']).to be_present
end
@@ -314,7 +314,7 @@ describe API::Groups, api: true do
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
expect(json_response.length).to eq(2)
- project_names = json_response.map { |proj| proj['name' ] }
+ project_names = json_response.map { |proj| proj['name'] }
expect(project_names).to match_array([project1.name, project3.name])
expect(json_response.first['visibility_level']).not_to be_present
end
@@ -398,7 +398,7 @@ describe API::Groups, api: true do
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
- project_names = json_response.map { |proj| proj['name' ] }
+ project_names = json_response.map { |proj| proj['name'] }
expect(project_names).to match_array([project1.name, project3.name])
end
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index ece1b43567d..7cb75310204 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -775,7 +775,7 @@ describe API::Issues, api: true do
expect(response).to have_http_status(201)
expect(json_response['title']).to eq('new issue')
expect(json_response['description']).to be_nil
- expect(json_response['labels']).to eq(['label', 'label2'])
+ expect(json_response['labels']).to eq(%w(label label2))
expect(json_response['confidential']).to be_falsy
end
@@ -1028,6 +1028,33 @@ describe API::Issues, api: true do
end
end
+ describe 'PUT /projects/:id/issues/:issue_id with spam filtering' do
+ let(:params) do
+ {
+ title: 'updated title',
+ description: 'content here',
+ labels: 'label, label2'
+ }
+ end
+
+ it "does not create a new project issue" do
+ allow_any_instance_of(SpamService).to receive_messages(check_for_spam?: true)
+ allow_any_instance_of(AkismetService).to receive_messages(is_spam?: true)
+
+ put api("/projects/#{project.id}/issues/#{issue.id}", user), params
+
+ expect(response).to have_http_status(400)
+ expect(json_response['message']).to eq({ "error" => "Spam detected" })
+
+ spam_logs = SpamLog.all
+ expect(spam_logs.count).to eq(1)
+ expect(spam_logs[0].title).to eq('updated title')
+ expect(spam_logs[0].description).to eq('content here')
+ expect(spam_logs[0].user).to eq(user)
+ expect(spam_logs[0].noteable_type).to eq('Issue')
+ end
+ end
+
describe 'PUT /projects/:id/issues/:issue_id to update labels' do
let!(:label) { create(:label, title: 'dummy', project: project) }
let!(:label_link) { create(:label_link, label: label, target: issue) }
@@ -1232,55 +1259,55 @@ describe API::Issues, api: true do
end
end
- describe 'POST :id/issues/:issue_id/subscription' do
+ describe 'POST :id/issues/:issue_id/subscribe' do
it 'subscribes to an issue' do
- post api("/projects/#{project.id}/issues/#{issue.id}/subscription", user2)
+ post api("/projects/#{project.id}/issues/#{issue.id}/subscribe", user2)
expect(response).to have_http_status(201)
expect(json_response['subscribed']).to eq(true)
end
it 'returns 304 if already subscribed' do
- post api("/projects/#{project.id}/issues/#{issue.id}/subscription", user)
+ post api("/projects/#{project.id}/issues/#{issue.id}/subscribe", user)
expect(response).to have_http_status(304)
end
it 'returns 404 if the issue is not found' do
- post api("/projects/#{project.id}/issues/123/subscription", user)
+ post api("/projects/#{project.id}/issues/123/subscribe", user)
expect(response).to have_http_status(404)
end
it 'returns 404 if the issue is confidential' do
- post api("/projects/#{project.id}/issues/#{confidential_issue.id}/subscription", non_member)
+ post api("/projects/#{project.id}/issues/#{confidential_issue.id}/subscribe", non_member)
expect(response).to have_http_status(404)
end
end
- describe 'DELETE :id/issues/:issue_id/subscription' do
+ describe 'POST :id/issues/:issue_id/unsubscribe' do
it 'unsubscribes from an issue' do
- delete api("/projects/#{project.id}/issues/#{issue.id}/subscription", user)
+ post api("/projects/#{project.id}/issues/#{issue.id}/unsubscribe", user)
- expect(response).to have_http_status(200)
+ expect(response).to have_http_status(201)
expect(json_response['subscribed']).to eq(false)
end
it 'returns 304 if not subscribed' do
- delete api("/projects/#{project.id}/issues/#{issue.id}/subscription", user2)
+ post api("/projects/#{project.id}/issues/#{issue.id}/unsubscribe", user2)
expect(response).to have_http_status(304)
end
it 'returns 404 if the issue is not found' do
- delete api("/projects/#{project.id}/issues/123/subscription", user)
+ post api("/projects/#{project.id}/issues/123/unsubscribe", user)
expect(response).to have_http_status(404)
end
it 'returns 404 if the issue is confidential' do
- delete api("/projects/#{project.id}/issues/#{confidential_issue.id}/subscription", non_member)
+ post api("/projects/#{project.id}/issues/#{confidential_issue.id}/unsubscribe", non_member)
expect(response).to have_http_status(404)
end
diff --git a/spec/requests/api/labels_spec.rb b/spec/requests/api/labels_spec.rb
index 5d7a76cf3be..af271dbd4f5 100644
--- a/spec/requests/api/labels_spec.rb
+++ b/spec/requests/api/labels_spec.rb
@@ -21,11 +21,11 @@ describe API::Labels, api: true do
create(:labeled_issue, project: project, labels: [label1], author: user, state: :closed)
create(:labeled_merge_request, labels: [priority_label], author: user, source_project: project )
- expected_keys = [
- 'id', 'name', 'color', 'description',
- 'open_issues_count', 'closed_issues_count', 'open_merge_requests_count',
- 'subscribed', 'priority'
- ]
+ expected_keys = %w(
+ id name color description
+ open_issues_count closed_issues_count open_merge_requests_count
+ subscribed priority
+ )
get api("/projects/#{project.id}/labels", user)
@@ -318,10 +318,10 @@ describe API::Labels, api: true do
end
end
- describe "POST /projects/:id/labels/:label_id/subscription" do
+ describe "POST /projects/:id/labels/:label_id/subscribe" do
context "when label_id is a label title" do
it "subscribes to the label" do
- post api("/projects/#{project.id}/labels/#{label1.title}/subscription", user)
+ post api("/projects/#{project.id}/labels/#{label1.title}/subscribe", user)
expect(response).to have_http_status(201)
expect(json_response["name"]).to eq(label1.title)
@@ -331,7 +331,7 @@ describe API::Labels, api: true do
context "when label_id is a label ID" do
it "subscribes to the label" do
- post api("/projects/#{project.id}/labels/#{label1.id}/subscription", user)
+ post api("/projects/#{project.id}/labels/#{label1.id}/subscribe", user)
expect(response).to have_http_status(201)
expect(json_response["name"]).to eq(label1.title)
@@ -343,7 +343,7 @@ describe API::Labels, api: true do
before { label1.subscribe(user, project) }
it "returns 304" do
- post api("/projects/#{project.id}/labels/#{label1.id}/subscription", user)
+ post api("/projects/#{project.id}/labels/#{label1.id}/subscribe", user)
expect(response).to have_http_status(304)
end
@@ -351,21 +351,21 @@ describe API::Labels, api: true do
context "when label ID is not found" do
it "returns 404 error" do
- post api("/projects/#{project.id}/labels/1234/subscription", user)
+ post api("/projects/#{project.id}/labels/1234/subscribe", user)
expect(response).to have_http_status(404)
end
end
end
- describe "DELETE /projects/:id/labels/:label_id/subscription" do
+ describe "POST /projects/:id/labels/:label_id/unsubscribe" do
before { label1.subscribe(user, project) }
context "when label_id is a label title" do
it "unsubscribes from the label" do
- delete api("/projects/#{project.id}/labels/#{label1.title}/subscription", user)
+ post api("/projects/#{project.id}/labels/#{label1.title}/unsubscribe", user)
- expect(response).to have_http_status(200)
+ expect(response).to have_http_status(201)
expect(json_response["name"]).to eq(label1.title)
expect(json_response["subscribed"]).to be_falsey
end
@@ -373,9 +373,9 @@ describe API::Labels, api: true do
context "when label_id is a label ID" do
it "unsubscribes from the label" do
- delete api("/projects/#{project.id}/labels/#{label1.id}/subscription", user)
+ post api("/projects/#{project.id}/labels/#{label1.id}/unsubscribe", user)
- expect(response).to have_http_status(200)
+ expect(response).to have_http_status(201)
expect(json_response["name"]).to eq(label1.title)
expect(json_response["subscribed"]).to be_falsey
end
@@ -385,7 +385,7 @@ describe API::Labels, api: true do
before { label1.unsubscribe(user, project) }
it "returns 304" do
- delete api("/projects/#{project.id}/labels/#{label1.id}/subscription", user)
+ post api("/projects/#{project.id}/labels/#{label1.id}/unsubscribe", user)
expect(response).to have_http_status(304)
end
@@ -393,7 +393,7 @@ describe API::Labels, api: true do
context "when label ID is not found" do
it "returns 404 error" do
- delete api("/projects/#{project.id}/labels/1234/subscription", user)
+ post api("/projects/#{project.id}/labels/1234/unsubscribe", user)
expect(response).to have_http_status(404)
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index f4dee4a4ca1..b87d0cd7de9 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -250,7 +250,7 @@ describe API::MergeRequests, api: true do
expect(response).to have_http_status(201)
expect(json_response['title']).to eq('Test merge_request')
- expect(json_response['labels']).to eq(['label', 'label2'])
+ expect(json_response['labels']).to eq(%w(label label2))
expect(json_response['milestone']['id']).to eq(milestone.id)
expect(json_response['force_remove_source_branch']).to be_truthy
end
@@ -662,22 +662,22 @@ describe API::MergeRequests, api: true do
end
end
- describe 'POST :id/merge_requests/:merge_request_id/subscription' do
+ describe 'POST :id/merge_requests/:merge_request_id/subscribe' do
it 'subscribes to a merge request' do
- post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscription", admin)
+ post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscribe", admin)
expect(response).to have_http_status(201)
expect(json_response['subscribed']).to eq(true)
end
it 'returns 304 if already subscribed' do
- post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscription", user)
+ post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscribe", user)
expect(response).to have_http_status(304)
end
it 'returns 404 if the merge request is not found' do
- post api("/projects/#{project.id}/merge_requests/123/subscription", user)
+ post api("/projects/#{project.id}/merge_requests/123/subscribe", user)
expect(response).to have_http_status(404)
end
@@ -686,28 +686,28 @@ describe API::MergeRequests, api: true do
guest = create(:user)
project.team << [guest, :guest]
- post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscription", guest)
+ post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscribe", guest)
expect(response).to have_http_status(403)
end
end
- describe 'DELETE :id/merge_requests/:merge_request_id/subscription' do
+ describe 'POST :id/merge_requests/:merge_request_id/unsubscribe' do
it 'unsubscribes from a merge request' do
- delete api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscription", user)
+ post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/unsubscribe", user)
- expect(response).to have_http_status(200)
+ expect(response).to have_http_status(201)
expect(json_response['subscribed']).to eq(false)
end
it 'returns 304 if not subscribed' do
- delete api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscription", admin)
+ post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/unsubscribe", admin)
expect(response).to have_http_status(304)
end
it 'returns 404 if the merge request is not found' do
- post api("/projects/#{project.id}/merge_requests/123/subscription", user)
+ post api("/projects/#{project.id}/merge_requests/123/unsubscribe", user)
expect(response).to have_http_status(404)
end
@@ -716,7 +716,7 @@ describe API::MergeRequests, api: true do
guest = create(:user)
project.team << [guest, :guest]
- delete api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscription", guest)
+ post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/unsubscribe", guest)
expect(response).to have_http_status(403)
end
diff --git a/spec/requests/api/project_snippets_spec.rb b/spec/requests/api/project_snippets_spec.rb
index f56876bcf54..da9df56401b 100644
--- a/spec/requests/api/project_snippets_spec.rb
+++ b/spec/requests/api/project_snippets_spec.rb
@@ -78,43 +78,33 @@ describe API::ProjectSnippets, api: true do
allow_any_instance_of(AkismetService).to receive(:is_spam?).and_return(true)
end
- context 'when the project is private' do
- let(:private_project) { create(:project_empty_repo, :private) }
-
- context 'when the snippet is public' do
- it 'creates the snippet' do
- expect { create_snippet(private_project, visibility_level: Snippet::PUBLIC) }.
- to change { Snippet.count }.by(1)
- end
+ context 'when the snippet is private' do
+ it 'creates the snippet' do
+ expect { create_snippet(project, visibility_level: Snippet::PRIVATE) }.
+ to change { Snippet.count }.by(1)
end
end
- context 'when the project is public' do
- context 'when the snippet is private' do
- it 'creates the snippet' do
- expect { create_snippet(project, visibility_level: Snippet::PRIVATE) }.
- to change { Snippet.count }.by(1)
- end
+ context 'when the snippet is public' do
+ it 'rejects the shippet' do
+ expect { create_snippet(project, visibility_level: Snippet::PUBLIC) }.
+ not_to change { Snippet.count }
+
+ expect(response).to have_http_status(400)
+ expect(json_response['message']).to eq({ "error" => "Spam detected" })
end
- context 'when the snippet is public' do
- it 'rejects the shippet' do
- expect { create_snippet(project, visibility_level: Snippet::PUBLIC) }.
- not_to change { Snippet.count }
- expect(response).to have_http_status(400)
- end
-
- it 'creates a spam log' do
- expect { create_snippet(project, visibility_level: Snippet::PUBLIC) }.
- to change { SpamLog.count }.by(1)
- end
+ it 'creates a spam log' do
+ expect { create_snippet(project, visibility_level: Snippet::PUBLIC) }.
+ to change { SpamLog.count }.by(1)
end
end
end
end
describe 'PUT /projects/:project_id/snippets/:id/' do
- let(:snippet) { create(:project_snippet, author: admin) }
+ let(:visibility_level) { Snippet::PUBLIC }
+ let(:snippet) { create(:project_snippet, author: admin, visibility_level: visibility_level) }
it 'updates snippet' do
new_content = 'New content'
@@ -138,6 +128,56 @@ describe API::ProjectSnippets, api: true do
expect(response).to have_http_status(400)
end
+
+ context 'when the snippet is spam' do
+ def update_snippet(snippet_params = {})
+ put api("/projects/#{snippet.project.id}/snippets/#{snippet.id}", admin), snippet_params
+ end
+
+ before do
+ allow_any_instance_of(AkismetService).to receive(:is_spam?).and_return(true)
+ end
+
+ context 'when the snippet is private' do
+ let(:visibility_level) { Snippet::PRIVATE }
+
+ it 'creates the snippet' do
+ expect { update_snippet(title: 'Foo') }.
+ to change { snippet.reload.title }.to('Foo')
+ end
+ end
+
+ context 'when the snippet is public' do
+ let(:visibility_level) { Snippet::PUBLIC }
+
+ it 'rejects the snippet' do
+ expect { update_snippet(title: 'Foo') }.
+ not_to change { snippet.reload.title }
+ end
+
+ it 'creates a spam log' do
+ expect { update_snippet(title: 'Foo') }.
+ to change { SpamLog.count }.by(1)
+ end
+ end
+
+ context 'when the private snippet is made public' do
+ let(:visibility_level) { Snippet::PRIVATE }
+
+ it 'rejects the snippet' do
+ expect { update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) }.
+ not_to change { snippet.reload.title }
+
+ expect(response).to have_http_status(400)
+ expect(json_response['message']).to eq({ "error" => "Spam detected" })
+ end
+
+ it 'creates a spam log' do
+ expect { update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) }.
+ to change { SpamLog.count }.by(1)
+ end
+ end
+ end
end
describe 'DELETE /projects/:project_id/snippets/:id/' do
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 4e90aae9279..8d139782fdf 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -121,7 +121,7 @@ describe API::Projects, api: true do
context 'and with simple=true' do
it 'returns a simplified version of all the projects' do
- expected_keys = ["id", "http_url_to_repo", "web_url", "name", "name_with_namespace", "path", "path_with_namespace"]
+ expected_keys = %w(id http_url_to_repo web_url name name_with_namespace path path_with_namespace)
get api('/projects?simple=true', user)
@@ -1422,4 +1422,53 @@ describe API::Projects, api: true do
end
end
end
+
+ describe 'POST /projects/:id/housekeeping' do
+ let(:housekeeping) { Projects::HousekeepingService.new(project) }
+
+ before do
+ allow(Projects::HousekeepingService).to receive(:new).with(project).and_return(housekeeping)
+ end
+
+ context 'when authenticated as owner' do
+ it 'starts the housekeeping process' do
+ expect(housekeeping).to receive(:execute).once
+
+ post api("/projects/#{project.id}/housekeeping", user)
+
+ expect(response).to have_http_status(201)
+ end
+
+ context 'when housekeeping lease is taken' do
+ it 'returns conflict' do
+ expect(housekeeping).to receive(:execute).once.and_raise(Projects::HousekeepingService::LeaseTaken)
+
+ post api("/projects/#{project.id}/housekeeping", user)
+
+ expect(response).to have_http_status(409)
+ expect(json_response['message']).to match(/Somebody already triggered housekeeping for this project/)
+ end
+ end
+ end
+
+ context 'when authenticated as developer' do
+ before do
+ project_member2
+ end
+
+ it 'returns forbidden error' do
+ post api("/projects/#{project.id}/housekeeping", user3)
+
+ expect(response).to have_http_status(403)
+ end
+ end
+
+ context 'when unauthenticated' do
+ it 'returns authentication error' do
+ post api("/projects/#{project.id}/housekeeping")
+
+ expect(response).to have_http_status(401)
+ end
+ end
+ end
end
diff --git a/spec/requests/api/snippets_spec.rb b/spec/requests/api/snippets_spec.rb
index 1ef92930b3c..41def7cd1d4 100644
--- a/spec/requests/api/snippets_spec.rb
+++ b/spec/requests/api/snippets_spec.rb
@@ -129,7 +129,9 @@ describe API::Snippets, api: true do
it 'rejects the shippet' do
expect { create_snippet(visibility_level: Snippet::PUBLIC) }.
not_to change { Snippet.count }
+
expect(response).to have_http_status(400)
+ expect(json_response['message']).to eq({ "error" => "Spam detected" })
end
it 'creates a spam log' do
@@ -141,16 +143,20 @@ describe API::Snippets, api: true do
end
describe 'PUT /snippets/:id' do
+ let(:visibility_level) { Snippet::PUBLIC }
let(:other_user) { create(:user) }
- let(:public_snippet) { create(:personal_snippet, :public, author: user) }
+ let(:snippet) do
+ create(:personal_snippet, author: user, visibility_level: visibility_level)
+ end
+
it 'updates snippet' do
new_content = 'New content'
- put api("/snippets/#{public_snippet.id}", user), content: new_content
+ put api("/snippets/#{snippet.id}", user), content: new_content
expect(response).to have_http_status(200)
- public_snippet.reload
- expect(public_snippet.content).to eq(new_content)
+ snippet.reload
+ expect(snippet.content).to eq(new_content)
end
it 'returns 404 for invalid snippet id' do
@@ -161,7 +167,7 @@ describe API::Snippets, api: true do
end
it "returns 404 for another user's snippet" do
- put api("/snippets/#{public_snippet.id}", other_user), title: 'fubar'
+ put api("/snippets/#{snippet.id}", other_user), title: 'fubar'
expect(response).to have_http_status(404)
expect(json_response['message']).to eq('404 Snippet Not Found')
@@ -172,6 +178,56 @@ describe API::Snippets, api: true do
expect(response).to have_http_status(400)
end
+
+ context 'when the snippet is spam' do
+ def update_snippet(snippet_params = {})
+ put api("/snippets/#{snippet.id}", user), snippet_params
+ end
+
+ before do
+ allow_any_instance_of(AkismetService).to receive(:is_spam?).and_return(true)
+ end
+
+ context 'when the snippet is private' do
+ let(:visibility_level) { Snippet::PRIVATE }
+
+ it 'updates the snippet' do
+ expect { update_snippet(title: 'Foo') }.
+ to change { snippet.reload.title }.to('Foo')
+ end
+ end
+
+ context 'when the snippet is public' do
+ let(:visibility_level) { Snippet::PUBLIC }
+
+ it 'rejects the shippet' do
+ expect { update_snippet(title: 'Foo') }.
+ not_to change { snippet.reload.title }
+
+ expect(response).to have_http_status(400)
+ expect(json_response['message']).to eq({ "error" => "Spam detected" })
+ end
+
+ it 'creates a spam log' do
+ expect { update_snippet(title: 'Foo') }.
+ to change { SpamLog.count }.by(1)
+ end
+ end
+
+ context 'when a private snippet is made public' do
+ let(:visibility_level) { Snippet::PRIVATE }
+
+ it 'rejects the snippet' do
+ expect { update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) }.
+ not_to change { snippet.reload.title }
+ end
+
+ it 'creates a spam log' do
+ expect { update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) }.
+ to change { SpamLog.count }.by(1)
+ end
+ end
+ end
end
describe 'DELETE /snippets/:id' do
diff --git a/spec/requests/api/templates_spec.rb b/spec/requests/api/templates_spec.rb
index 8506e8fccde..2c83e119065 100644
--- a/spec/requests/api/templates_spec.rb
+++ b/spec/requests/api/templates_spec.rb
@@ -58,11 +58,11 @@ describe API::Templates, api: true do
expect(json_response['popular']).to be true
expect(json_response['html_url']).to eq('http://choosealicense.com/licenses/mit/')
expect(json_response['source_url']).to eq('https://opensource.org/licenses/MIT')
- expect(json_response['description']).to include('A permissive license that is short and to the point.')
+ expect(json_response['description']).to include('A short and simple permissive license with conditions')
expect(json_response['conditions']).to eq(%w[include-copyright])
expect(json_response['permissions']).to eq(%w[commercial-use modifications distribution private-use])
expect(json_response['limitations']).to eq(%w[no-liability])
- expect(json_response['content']).to include('The MIT License (MIT)')
+ expect(json_response['content']).to include('MIT License')
end
end
@@ -73,7 +73,7 @@ describe API::Templates, api: true do
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
- expect(json_response.size).to eq(15)
+ expect(json_response.size).to eq(12)
expect(json_response.map { |l| l['key'] }).to include('agpl-3.0')
end
@@ -102,7 +102,7 @@ describe API::Templates, api: true do
let(:license_type) { 'mit' }
it 'returns the license text' do
- expect(json_response['content']).to include('The MIT License (MIT)')
+ expect(json_response['content']).to include('MIT License')
end
it 'replaces placeholder values' do
diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb
index 2069d2a7c75..f35e963a14b 100644
--- a/spec/requests/api/todos_spec.rb
+++ b/spec/requests/api/todos_spec.rb
@@ -107,46 +107,47 @@ describe API::Todos, api: true do
end
end
- describe 'DELETE /todos/:id' do
+ describe 'POST /todos/:id/mark_as_done' do
context 'when unauthenticated' do
it 'returns authentication error' do
- delete api("/todos/#{pending_1.id}")
+ post api("/todos/#{pending_1.id}/mark_as_done")
- expect(response.status).to eq(401)
+ expect(response).to have_http_status(401)
end
end
context 'when authenticated' do
it 'marks a todo as done' do
- delete api("/todos/#{pending_1.id}", john_doe)
+ post api("/todos/#{pending_1.id}/mark_as_done", john_doe)
- expect(response.status).to eq(200)
+ expect(response).to have_http_status(201)
+ expect(json_response['id']).to eq(pending_1.id)
+ expect(json_response['state']).to eq('done')
expect(pending_1.reload).to be_done
end
it 'updates todos cache' do
expect_any_instance_of(User).to receive(:update_todos_count_cache).and_call_original
- delete api("/todos/#{pending_1.id}", john_doe)
+ post api("/todos/#{pending_1.id}/mark_as_done", john_doe)
end
end
end
- describe 'DELETE /todos' do
+ describe 'POST /mark_as_done' do
context 'when unauthenticated' do
it 'returns authentication error' do
- delete api('/todos')
+ post api('/todos/mark_as_done')
- expect(response.status).to eq(401)
+ expect(response).to have_http_status(401)
end
end
context 'when authenticated' do
it 'marks all todos as done' do
- delete api('/todos', john_doe)
+ post api('/todos/mark_as_done', john_doe)
- expect(response.status).to eq(200)
- expect(response.body).to eq('3')
+ expect(response).to have_http_status(204)
expect(pending_1.reload).to be_done
expect(pending_2.reload).to be_done
expect(pending_3.reload).to be_done
@@ -155,7 +156,7 @@ describe API::Todos, api: true do
it 'updates todos cache' do
expect_any_instance_of(User).to receive(:update_todos_count_cache).and_call_original
- delete api("/todos", john_doe)
+ post api("/todos/mark_as_done", john_doe)
end
end
end
diff --git a/spec/requests/api/v3/commits_spec.rb b/spec/requests/api/v3/commits_spec.rb
new file mode 100644
index 00000000000..2d7584c3e59
--- /dev/null
+++ b/spec/requests/api/v3/commits_spec.rb
@@ -0,0 +1,578 @@
+require 'spec_helper'
+require 'mime/types'
+
+describe API::V3::Commits, api: true do
+ include ApiHelpers
+ let(:user) { create(:user) }
+ let(:user2) { create(:user) }
+ let!(:project) { create(:project, :repository, creator: user, namespace: user.namespace) }
+ let!(:master) { create(:project_member, :master, user: user, project: project) }
+ let!(:guest) { create(:project_member, :guest, user: user2, project: project) }
+ let!(:note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'a comment on a commit') }
+ let!(:another_note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'another comment on a commit') }
+
+ before { project.team << [user, :reporter] }
+
+ describe "List repository commits" do
+ context "authorized user" do
+ before { project.team << [user2, :reporter] }
+
+ it "returns project commits" do
+ commit = project.repository.commit
+ get v3_api("/projects/#{project.id}/repository/commits", user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first['id']).to eq(commit.id)
+ expect(json_response.first['committer_name']).to eq(commit.committer_name)
+ expect(json_response.first['committer_email']).to eq(commit.committer_email)
+ end
+ end
+
+ context "unauthorized user" do
+ it "does not return project commits" do
+ get v3_api("/projects/#{project.id}/repository/commits")
+ expect(response).to have_http_status(401)
+ end
+ end
+
+ context "since optional parameter" do
+ it "returns project commits since provided parameter" do
+ commits = project.repository.commits("master")
+ since = commits.second.created_at
+
+ get v3_api("/projects/#{project.id}/repository/commits?since=#{since.utc.iso8601}", user)
+
+ expect(json_response.size).to eq 2
+ expect(json_response.first["id"]).to eq(commits.first.id)
+ expect(json_response.second["id"]).to eq(commits.second.id)
+ end
+ end
+
+ context "until optional parameter" do
+ it "returns project commits until provided parameter" do
+ commits = project.repository.commits("master")
+ before = commits.second.created_at
+
+ get v3_api("/projects/#{project.id}/repository/commits?until=#{before.utc.iso8601}", user)
+
+ if commits.size >= 20
+ expect(json_response.size).to eq(20)
+ else
+ expect(json_response.size).to eq(commits.size - 1)
+ end
+
+ expect(json_response.first["id"]).to eq(commits.second.id)
+ expect(json_response.second["id"]).to eq(commits.third.id)
+ end
+ end
+
+ context "invalid xmlschema date parameters" do
+ it "returns an invalid parameter error message" do
+ get v3_api("/projects/#{project.id}/repository/commits?since=invalid-date", user)
+
+ expect(response).to have_http_status(400)
+ expect(json_response['error']).to eq('since is invalid')
+ end
+ end
+
+ context "path optional parameter" do
+ it "returns project commits matching provided path parameter" do
+ path = 'files/ruby/popen.rb'
+
+ get v3_api("/projects/#{project.id}/repository/commits?path=#{path}", user)
+
+ expect(json_response.size).to eq(3)
+ expect(json_response.first["id"]).to eq("570e7b2abdd848b95f2f578043fc23bd6f6fd24d")
+ end
+ end
+ end
+
+ describe "Create a commit with multiple files and actions" do
+ let!(:url) { "/projects/#{project.id}/repository/commits" }
+
+ it 'returns a 403 unauthorized for user without permissions' do
+ post v3_api(url, user2)
+
+ expect(response).to have_http_status(403)
+ end
+
+ it 'returns a 400 bad request if no params are given' do
+ post v3_api(url, user)
+
+ expect(response).to have_http_status(400)
+ end
+
+ context :create do
+ let(:message) { 'Created file' }
+ let!(:invalid_c_params) do
+ {
+ branch_name: 'master',
+ commit_message: message,
+ actions: [
+ {
+ action: 'create',
+ file_path: 'files/ruby/popen.rb',
+ content: 'puts 8'
+ }
+ ]
+ }
+ end
+ let!(:valid_c_params) do
+ {
+ branch_name: 'master',
+ commit_message: message,
+ actions: [
+ {
+ action: 'create',
+ file_path: 'foo/bar/baz.txt',
+ content: 'puts 8'
+ }
+ ]
+ }
+ end
+
+ it 'a new file in project repo' do
+ post v3_api(url, user), valid_c_params
+
+ expect(response).to have_http_status(201)
+ expect(json_response['title']).to eq(message)
+ expect(json_response['committer_name']).to eq(user.name)
+ expect(json_response['committer_email']).to eq(user.email)
+ end
+
+ it 'returns a 400 bad request if file exists' do
+ post v3_api(url, user), invalid_c_params
+
+ expect(response).to have_http_status(400)
+ end
+
+ context 'with project path in URL' do
+ let(:url) { "/projects/#{project.namespace.path}%2F#{project.path}/repository/commits" }
+
+ it 'a new file in project repo' do
+ post v3_api(url, user), valid_c_params
+
+ expect(response).to have_http_status(201)
+ end
+ end
+ end
+
+ context :delete do
+ let(:message) { 'Deleted file' }
+ let!(:invalid_d_params) do
+ {
+ branch_name: 'markdown',
+ commit_message: message,
+ actions: [
+ {
+ action: 'delete',
+ file_path: 'doc/api/projects.md'
+ }
+ ]
+ }
+ end
+ let!(:valid_d_params) do
+ {
+ branch_name: 'markdown',
+ commit_message: message,
+ actions: [
+ {
+ action: 'delete',
+ file_path: 'doc/api/users.md'
+ }
+ ]
+ }
+ end
+
+ it 'an existing file in project repo' do
+ post v3_api(url, user), valid_d_params
+
+ expect(response).to have_http_status(201)
+ expect(json_response['title']).to eq(message)
+ end
+
+ it 'returns a 400 bad request if file does not exist' do
+ post v3_api(url, user), invalid_d_params
+
+ expect(response).to have_http_status(400)
+ end
+ end
+
+ context :move do
+ let(:message) { 'Moved file' }
+ let!(:invalid_m_params) do
+ {
+ branch_name: 'feature',
+ commit_message: message,
+ actions: [
+ {
+ action: 'move',
+ file_path: 'CHANGELOG',
+ previous_path: 'VERSION',
+ content: '6.7.0.pre'
+ }
+ ]
+ }
+ end
+ let!(:valid_m_params) do
+ {
+ branch_name: 'feature',
+ commit_message: message,
+ actions: [
+ {
+ action: 'move',
+ file_path: 'VERSION.txt',
+ previous_path: 'VERSION',
+ content: '6.7.0.pre'
+ }
+ ]
+ }
+ end
+
+ it 'an existing file in project repo' do
+ post v3_api(url, user), valid_m_params
+
+ expect(response).to have_http_status(201)
+ expect(json_response['title']).to eq(message)
+ end
+
+ it 'returns a 400 bad request if file does not exist' do
+ post v3_api(url, user), invalid_m_params
+
+ expect(response).to have_http_status(400)
+ end
+ end
+
+ context :update do
+ let(:message) { 'Updated file' }
+ let!(:invalid_u_params) do
+ {
+ branch_name: 'master',
+ commit_message: message,
+ actions: [
+ {
+ action: 'update',
+ file_path: 'foo/bar.baz',
+ content: 'puts 8'
+ }
+ ]
+ }
+ end
+ let!(:valid_u_params) do
+ {
+ branch_name: 'master',
+ commit_message: message,
+ actions: [
+ {
+ action: 'update',
+ file_path: 'files/ruby/popen.rb',
+ content: 'puts 8'
+ }
+ ]
+ }
+ end
+
+ it 'an existing file in project repo' do
+ post v3_api(url, user), valid_u_params
+
+ expect(response).to have_http_status(201)
+ expect(json_response['title']).to eq(message)
+ end
+
+ it 'returns a 400 bad request if file does not exist' do
+ post v3_api(url, user), invalid_u_params
+
+ expect(response).to have_http_status(400)
+ end
+ end
+
+ context "multiple operations" do
+ let(:message) { 'Multiple actions' }
+ let!(:invalid_mo_params) do
+ {
+ branch_name: 'master',
+ commit_message: message,
+ actions: [
+ {
+ action: 'create',
+ file_path: 'files/ruby/popen.rb',
+ content: 'puts 8'
+ },
+ {
+ action: 'delete',
+ file_path: 'doc/v3_api/projects.md'
+ },
+ {
+ action: 'move',
+ file_path: 'CHANGELOG',
+ previous_path: 'VERSION',
+ content: '6.7.0.pre'
+ },
+ {
+ action: 'update',
+ file_path: 'foo/bar.baz',
+ content: 'puts 8'
+ }
+ ]
+ }
+ end
+ let!(:valid_mo_params) do
+ {
+ branch_name: 'master',
+ commit_message: message,
+ actions: [
+ {
+ action: 'create',
+ file_path: 'foo/bar/baz.txt',
+ content: 'puts 8'
+ },
+ {
+ action: 'delete',
+ file_path: 'Gemfile.zip'
+ },
+ {
+ action: 'move',
+ file_path: 'VERSION.txt',
+ previous_path: 'VERSION',
+ content: '6.7.0.pre'
+ },
+ {
+ action: 'update',
+ file_path: 'files/ruby/popen.rb',
+ content: 'puts 8'
+ }
+ ]
+ }
+ end
+
+ it 'are commited as one in project repo' do
+ post v3_api(url, user), valid_mo_params
+
+ expect(response).to have_http_status(201)
+ expect(json_response['title']).to eq(message)
+ end
+
+ it 'return a 400 bad request if there are any issues' do
+ post v3_api(url, user), invalid_mo_params
+
+ expect(response).to have_http_status(400)
+ end
+ end
+ end
+
+ describe "Get a single commit" do
+ context "authorized user" do
+ it "returns a commit by sha" do
+ get v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response['id']).to eq(project.repository.commit.id)
+ expect(json_response['title']).to eq(project.repository.commit.title)
+ expect(json_response['stats']['additions']).to eq(project.repository.commit.stats.additions)
+ expect(json_response['stats']['deletions']).to eq(project.repository.commit.stats.deletions)
+ expect(json_response['stats']['total']).to eq(project.repository.commit.stats.total)
+ end
+
+ it "returns a 404 error if not found" do
+ get v3_api("/projects/#{project.id}/repository/commits/invalid_sha", user)
+ expect(response).to have_http_status(404)
+ end
+
+ it "returns nil for commit without CI" do
+ get v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response['status']).to be_nil
+ end
+
+ it "returns status for CI" do
+ pipeline = project.ensure_pipeline('master', project.repository.commit.sha)
+ pipeline.update(status: 'success')
+
+ get v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response['status']).to eq(pipeline.status)
+ end
+
+ it "returns status for CI when pipeline is created" do
+ project.ensure_pipeline('master', project.repository.commit.sha)
+
+ get v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response['status']).to eq("created")
+ end
+ end
+
+ context "unauthorized user" do
+ it "does not return the selected commit" do
+ get v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}")
+ expect(response).to have_http_status(401)
+ end
+ end
+ end
+
+ describe "Get the diff of a commit" do
+ context "authorized user" do
+ before { project.team << [user2, :reporter] }
+
+ it "returns the diff of the selected commit" do
+ get v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/diff", user)
+ expect(response).to have_http_status(200)
+
+ expect(json_response).to be_an Array
+ expect(json_response.length).to be >= 1
+ expect(json_response.first.keys).to include "diff"
+ end
+
+ it "returns a 404 error if invalid commit" do
+ get v3_api("/projects/#{project.id}/repository/commits/invalid_sha/diff", user)
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context "unauthorized user" do
+ it "does not return the diff of the selected commit" do
+ get v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/diff")
+ expect(response).to have_http_status(401)
+ end
+ end
+ end
+
+ describe 'Get the comments of a commit' do
+ context 'authorized user' do
+ it 'returns merge_request comments' do
+ get v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments", user)
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(2)
+ expect(json_response.first['note']).to eq('a comment on a commit')
+ expect(json_response.first['author']['id']).to eq(user.id)
+ end
+
+ it 'returns a 404 error if merge_request_id not found' do
+ get v3_api("/projects/#{project.id}/repository/commits/1234ab/comments", user)
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'unauthorized user' do
+ it 'does not return the diff of the selected commit' do
+ get v3_api("/projects/#{project.id}/repository/commits/1234ab/comments")
+ expect(response).to have_http_status(401)
+ end
+ end
+ end
+
+ describe 'POST :id/repository/commits/:sha/cherry_pick' do
+ let(:master_pickable_commit) { project.commit('7d3b0f7cff5f37573aea97cebfd5692ea1689924') }
+
+ context 'authorized user' do
+ it 'cherry picks a commit' do
+ post v3_api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user), branch: 'master'
+
+ expect(response).to have_http_status(201)
+ expect(json_response['title']).to eq(master_pickable_commit.title)
+ expect(json_response['message']).to eq(master_pickable_commit.message)
+ expect(json_response['author_name']).to eq(master_pickable_commit.author_name)
+ expect(json_response['committer_name']).to eq(user.name)
+ end
+
+ it 'returns 400 if commit is already included in the target branch' do
+ post v3_api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user), branch: 'markdown'
+
+ expect(response).to have_http_status(400)
+ expect(json_response['message']).to eq('Sorry, we cannot cherry-pick this commit automatically.
+ A cherry-pick may have already been performed with this commit, or a more recent commit may have updated some of its content.')
+ end
+
+ it 'returns 400 if you are not allowed to push to the target branch' do
+ project.team << [user2, :developer]
+ protected_branch = create(:protected_branch, project: project, name: 'feature')
+
+ post v3_api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user2), branch: protected_branch.name
+
+ expect(response).to have_http_status(400)
+ expect(json_response['message']).to eq('You are not allowed to push into this branch')
+ end
+
+ it 'returns 400 for missing parameters' do
+ post v3_api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user)
+
+ expect(response).to have_http_status(400)
+ expect(json_response['error']).to eq('branch is missing')
+ end
+
+ it 'returns 404 if commit is not found' do
+ post v3_api("/projects/#{project.id}/repository/commits/abcd0123/cherry_pick", user), branch: 'master'
+
+ expect(response).to have_http_status(404)
+ expect(json_response['message']).to eq('404 Commit Not Found')
+ end
+
+ it 'returns 404 if branch is not found' do
+ post v3_api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user), branch: 'foo'
+
+ expect(response).to have_http_status(404)
+ expect(json_response['message']).to eq('404 Branch Not Found')
+ end
+
+ it 'returns 400 for missing parameters' do
+ post v3_api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user)
+
+ expect(response).to have_http_status(400)
+ expect(json_response['error']).to eq('branch is missing')
+ end
+ end
+
+ context 'unauthorized user' do
+ it 'does not cherry pick the commit' do
+ post v3_api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick"), branch: 'master'
+
+ expect(response).to have_http_status(401)
+ end
+ end
+ end
+
+ describe 'Post comment to commit' do
+ context 'authorized user' do
+ it 'returns comment' do
+ post v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments", user), note: 'My comment'
+ expect(response).to have_http_status(201)
+ expect(json_response['note']).to eq('My comment')
+ expect(json_response['path']).to be_nil
+ expect(json_response['line']).to be_nil
+ expect(json_response['line_type']).to be_nil
+ end
+
+ it 'returns the inline comment' do
+ post v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments", user), note: 'My comment', path: project.repository.commit.raw_diffs.first.new_path, line: 1, line_type: 'new'
+
+ expect(response).to have_http_status(201)
+ expect(json_response['note']).to eq('My comment')
+ expect(json_response['path']).to eq(project.repository.commit.raw_diffs.first.new_path)
+ expect(json_response['line']).to eq(1)
+ expect(json_response['line_type']).to eq('new')
+ end
+
+ it 'returns 400 if note is missing' do
+ post v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments", user)
+ expect(response).to have_http_status(400)
+ end
+
+ it 'returns 404 if note is attached to non existent commit' do
+ post v3_api("/projects/#{project.id}/repository/commits/1234ab/comments", user), note: 'My comment'
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'unauthorized user' do
+ it 'does not return the diff of the selected commit' do
+ post v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments")
+ expect(response).to have_http_status(401)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/v3/files_spec.rb b/spec/requests/api/v3/files_spec.rb
new file mode 100644
index 00000000000..4af05605ec6
--- /dev/null
+++ b/spec/requests/api/v3/files_spec.rb
@@ -0,0 +1,270 @@
+require 'spec_helper'
+
+describe API::V3::Files, api: true do
+ include ApiHelpers
+ let(:user) { create(:user) }
+ let!(:project) { create(:project, :repository, namespace: user.namespace ) }
+ let(:guest) { create(:user) { |u| project.add_guest(u) } }
+ let(:file_path) { 'files/ruby/popen.rb' }
+ let(:params) do
+ {
+ file_path: file_path,
+ ref: 'master'
+ }
+ end
+ let(:author_email) { FFaker::Internet.email }
+
+ # I have to remove periods from the end of the name
+ # This happened when the user's name had a suffix (i.e. "Sr.")
+ # This seems to be what git does under the hood. For example, this commit:
+ #
+ # $ git commit --author='Foo Sr. <foo@example.com>' -m 'Where's my trailing period?'
+ #
+ # results in this:
+ #
+ # $ git show --pretty
+ # ...
+ # Author: Foo Sr <foo@example.com>
+ # ...
+ let(:author_name) { FFaker::Name.name.chomp("\.") }
+
+ before { project.team << [user, :developer] }
+
+ describe "GET /projects/:id/repository/files" do
+ let(:route) { "/projects/#{project.id}/repository/files" }
+
+ shared_examples_for 'repository files' do
+ it "returns file info" do
+ get v3_api(route, current_user), params
+
+ expect(response).to have_http_status(200)
+ expect(json_response['file_path']).to eq(file_path)
+ expect(json_response['file_name']).to eq('popen.rb')
+ expect(json_response['last_commit_id']).to eq('570e7b2abdd848b95f2f578043fc23bd6f6fd24d')
+ expect(Base64.decode64(json_response['content']).lines.first).to eq("require 'fileutils'\n")
+ end
+
+ context 'when no params are given' do
+ it_behaves_like '400 response' do
+ let(:request) { get v3_api(route, current_user) }
+ end
+ end
+
+ context 'when file_path does not exist' do
+ let(:params) do
+ {
+ file_path: 'app/models/application.rb',
+ ref: 'master',
+ }
+ end
+
+ it_behaves_like '404 response' do
+ let(:request) { get v3_api(route, current_user), params }
+ let(:message) { '404 File Not Found' }
+ end
+ end
+
+ context 'when repository is disabled' do
+ include_context 'disabled repository'
+
+ it_behaves_like '403 response' do
+ let(:request) { get v3_api(route, current_user), params }
+ end
+ end
+ end
+
+ context 'when unauthenticated', 'and project is public' do
+ it_behaves_like 'repository files' do
+ let(:project) { create(:project, :public) }
+ let(:current_user) { nil }
+ end
+ end
+
+ context 'when unauthenticated', 'and project is private' do
+ it_behaves_like '404 response' do
+ let(:request) { get v3_api(route), params }
+ let(:message) { '404 Project Not Found' }
+ end
+ end
+
+ context 'when authenticated', 'as a developer' do
+ it_behaves_like 'repository files' do
+ let(:current_user) { user }
+ end
+ end
+
+ context 'when authenticated', 'as a guest' do
+ it_behaves_like '403 response' do
+ let(:request) { get v3_api(route, guest), params }
+ end
+ end
+ end
+
+ describe "POST /projects/:id/repository/files" do
+ let(:valid_params) do
+ {
+ file_path: 'newfile.rb',
+ branch_name: 'master',
+ content: 'puts 8',
+ commit_message: 'Added newfile'
+ }
+ end
+
+ it "creates a new file in project repo" do
+ post v3_api("/projects/#{project.id}/repository/files", user), valid_params
+
+ expect(response).to have_http_status(201)
+ expect(json_response['file_path']).to eq('newfile.rb')
+ last_commit = project.repository.commit.raw
+ expect(last_commit.author_email).to eq(user.email)
+ expect(last_commit.author_name).to eq(user.name)
+ end
+
+ it "returns a 400 bad request if no params given" do
+ post v3_api("/projects/#{project.id}/repository/files", user)
+
+ expect(response).to have_http_status(400)
+ end
+
+ it "returns a 400 if editor fails to create file" do
+ allow_any_instance_of(Repository).to receive(:commit_file).
+ and_return(false)
+
+ post v3_api("/projects/#{project.id}/repository/files", user), valid_params
+
+ expect(response).to have_http_status(400)
+ end
+
+ context "when specifying an author" do
+ it "creates a new file with the specified author" do
+ valid_params.merge!(author_email: author_email, author_name: author_name)
+
+ post v3_api("/projects/#{project.id}/repository/files", user), valid_params
+
+ expect(response).to have_http_status(201)
+ last_commit = project.repository.commit.raw
+ expect(last_commit.author_email).to eq(author_email)
+ expect(last_commit.author_name).to eq(author_name)
+ end
+ end
+ end
+
+ describe "PUT /projects/:id/repository/files" do
+ let(:valid_params) do
+ {
+ file_path: file_path,
+ branch_name: 'master',
+ content: 'puts 8',
+ commit_message: 'Changed file'
+ }
+ end
+
+ it "updates existing file in project repo" do
+ put v3_api("/projects/#{project.id}/repository/files", user), valid_params
+
+ expect(response).to have_http_status(200)
+ expect(json_response['file_path']).to eq(file_path)
+ last_commit = project.repository.commit.raw
+ expect(last_commit.author_email).to eq(user.email)
+ expect(last_commit.author_name).to eq(user.name)
+ end
+
+ it "returns a 400 bad request if no params given" do
+ put v3_api("/projects/#{project.id}/repository/files", user)
+
+ expect(response).to have_http_status(400)
+ end
+
+ context "when specifying an author" do
+ it "updates a file with the specified author" do
+ valid_params.merge!(author_email: author_email, author_name: author_name, content: "New content")
+
+ put v3_api("/projects/#{project.id}/repository/files", user), valid_params
+
+ expect(response).to have_http_status(200)
+ last_commit = project.repository.commit.raw
+ expect(last_commit.author_email).to eq(author_email)
+ expect(last_commit.author_name).to eq(author_name)
+ end
+ end
+ end
+
+ describe "DELETE /projects/:id/repository/files" do
+ let(:valid_params) do
+ {
+ file_path: file_path,
+ branch_name: 'master',
+ commit_message: 'Changed file'
+ }
+ end
+
+ it "deletes existing file in project repo" do
+ delete v3_api("/projects/#{project.id}/repository/files", user), valid_params
+
+ expect(response).to have_http_status(200)
+ expect(json_response['file_path']).to eq(file_path)
+ last_commit = project.repository.commit.raw
+ expect(last_commit.author_email).to eq(user.email)
+ expect(last_commit.author_name).to eq(user.name)
+ end
+
+ it "returns a 400 bad request if no params given" do
+ delete v3_api("/projects/#{project.id}/repository/files", user)
+
+ expect(response).to have_http_status(400)
+ end
+
+ it "returns a 400 if fails to create file" do
+ allow_any_instance_of(Repository).to receive(:remove_file).and_return(false)
+
+ delete v3_api("/projects/#{project.id}/repository/files", user), valid_params
+
+ expect(response).to have_http_status(400)
+ end
+
+ context "when specifying an author" do
+ it "removes a file with the specified author" do
+ valid_params.merge!(author_email: author_email, author_name: author_name)
+
+ delete v3_api("/projects/#{project.id}/repository/files", user), valid_params
+
+ expect(response).to have_http_status(200)
+ last_commit = project.repository.commit.raw
+ expect(last_commit.author_email).to eq(author_email)
+ expect(last_commit.author_name).to eq(author_name)
+ end
+ end
+ end
+
+ describe "POST /projects/:id/repository/files with binary file" do
+ let(:file_path) { 'test.bin' }
+ let(:put_params) do
+ {
+ file_path: file_path,
+ branch_name: 'master',
+ content: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=',
+ commit_message: 'Binary file with a \n should not be touched',
+ encoding: 'base64'
+ }
+ end
+ let(:get_params) do
+ {
+ file_path: file_path,
+ ref: 'master',
+ }
+ end
+
+ before do
+ post v3_api("/projects/#{project.id}/repository/files", user), put_params
+ end
+
+ it "remains unchanged" do
+ get v3_api("/projects/#{project.id}/repository/files", user), get_params
+
+ expect(response).to have_http_status(200)
+ expect(json_response['file_path']).to eq(file_path)
+ expect(json_response['file_name']).to eq(file_path)
+ expect(json_response['content']).to eq(put_params[:content])
+ end
+ end
+end
diff --git a/spec/requests/api/v3/issues_spec.rb b/spec/requests/api/v3/issues_spec.rb
index 33a127de98a..803acd55470 100644
--- a/spec/requests/api/v3/issues_spec.rb
+++ b/spec/requests/api/v3/issues_spec.rb
@@ -722,7 +722,7 @@ describe API::V3::Issues, api: true do
expect(response).to have_http_status(201)
expect(json_response['title']).to eq('new issue')
expect(json_response['description']).to be_nil
- expect(json_response['labels']).to eq(['label', 'label2'])
+ expect(json_response['labels']).to eq(%w(label label2))
expect(json_response['confidential']).to be_falsy
end
@@ -986,6 +986,33 @@ describe API::V3::Issues, api: true do
end
end
+ describe 'PUT /projects/:id/issues/:issue_id with spam filtering' do
+ let(:params) do
+ {
+ title: 'updated title',
+ description: 'content here',
+ labels: 'label, label2'
+ }
+ end
+
+ it "does not create a new project issue" do
+ allow_any_instance_of(SpamService).to receive_messages(check_for_spam?: true)
+ allow_any_instance_of(AkismetService).to receive_messages(is_spam?: true)
+
+ put v3_api("/projects/#{project.id}/issues/#{issue.id}", user), params
+
+ expect(response).to have_http_status(400)
+ expect(json_response['message']).to eq({ "error" => "Spam detected" })
+
+ spam_logs = SpamLog.all
+ expect(spam_logs.count).to eq(1)
+ expect(spam_logs[0].title).to eq('updated title')
+ expect(spam_logs[0].description).to eq('content here')
+ expect(spam_logs[0].user).to eq(user)
+ expect(spam_logs[0].noteable_type).to eq('Issue')
+ end
+ end
+
describe 'PUT /projects/:id/issues/:issue_id to update labels' do
let!(:label) { create(:label, title: 'dummy', project: project) }
let!(:label_link) { create(:label_link, label: label, target: issue) }
diff --git a/spec/requests/api/v3/labels_spec.rb b/spec/requests/api/v3/labels_spec.rb
index 18e2c0d40c8..f44403374e9 100644
--- a/spec/requests/api/v3/labels_spec.rb
+++ b/spec/requests/api/v3/labels_spec.rb
@@ -21,11 +21,11 @@ describe API::V3::Labels, api: true do
create(:labeled_issue, project: project, labels: [label1], author: user, state: :closed)
create(:labeled_merge_request, labels: [priority_label], author: user, source_project: project )
- expected_keys = [
- 'id', 'name', 'color', 'description',
- 'open_issues_count', 'closed_issues_count', 'open_merge_requests_count',
- 'subscribed', 'priority'
- ]
+ expected_keys = %w(
+ id name color description
+ open_issues_count closed_issues_count open_merge_requests_count
+ subscribed priority
+ )
get v3_api("/projects/#{project.id}/labels", user)
@@ -67,4 +67,86 @@ describe API::V3::Labels, api: true do
expect(priority_label_response['subscribed']).to be_falsey
end
end
+
+ describe "POST /projects/:id/labels/:label_id/subscription" do
+ context "when label_id is a label title" do
+ it "subscribes to the label" do
+ post v3_api("/projects/#{project.id}/labels/#{label1.title}/subscription", user)
+
+ expect(response).to have_http_status(201)
+ expect(json_response["name"]).to eq(label1.title)
+ expect(json_response["subscribed"]).to be_truthy
+ end
+ end
+
+ context "when label_id is a label ID" do
+ it "subscribes to the label" do
+ post v3_api("/projects/#{project.id}/labels/#{label1.id}/subscription", user)
+
+ expect(response).to have_http_status(201)
+ expect(json_response["name"]).to eq(label1.title)
+ expect(json_response["subscribed"]).to be_truthy
+ end
+ end
+
+ context "when user is already subscribed to label" do
+ before { label1.subscribe(user, project) }
+
+ it "returns 304" do
+ post v3_api("/projects/#{project.id}/labels/#{label1.id}/subscription", user)
+
+ expect(response).to have_http_status(304)
+ end
+ end
+
+ context "when label ID is not found" do
+ it "returns 404 error" do
+ post v3_api("/projects/#{project.id}/labels/1234/subscription", user)
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+
+ describe "DELETE /projects/:id/labels/:label_id/subscription" do
+ before { label1.subscribe(user, project) }
+
+ context "when label_id is a label title" do
+ it "unsubscribes from the label" do
+ delete v3_api("/projects/#{project.id}/labels/#{label1.title}/subscription", user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response["name"]).to eq(label1.title)
+ expect(json_response["subscribed"]).to be_falsey
+ end
+ end
+
+ context "when label_id is a label ID" do
+ it "unsubscribes from the label" do
+ delete v3_api("/projects/#{project.id}/labels/#{label1.id}/subscription", user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response["name"]).to eq(label1.title)
+ expect(json_response["subscribed"]).to be_falsey
+ end
+ end
+
+ context "when user is already unsubscribed from label" do
+ before { label1.unsubscribe(user, project) }
+
+ it "returns 304" do
+ delete v3_api("/projects/#{project.id}/labels/#{label1.id}/subscription", user)
+
+ expect(response).to have_http_status(304)
+ end
+ end
+
+ context "when label ID is not found" do
+ it "returns 404 error" do
+ delete v3_api("/projects/#{project.id}/labels/1234/subscription", user)
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
end
diff --git a/spec/requests/api/v3/merge_requests_spec.rb b/spec/requests/api/v3/merge_requests_spec.rb
index b94e1ef4ced..51764d1000e 100644
--- a/spec/requests/api/v3/merge_requests_spec.rb
+++ b/spec/requests/api/v3/merge_requests_spec.rb
@@ -237,7 +237,7 @@ describe API::MergeRequests, api: true do
expect(response).to have_http_status(201)
expect(json_response['title']).to eq('Test merge_request')
- expect(json_response['labels']).to eq(['label', 'label2'])
+ expect(json_response['labels']).to eq(%w(label label2))
expect(json_response['milestone']['id']).to eq(milestone.id)
expect(json_response['force_remove_source_branch']).to be_truthy
end
diff --git a/spec/requests/api/v3/notes_spec.rb b/spec/requests/api/v3/notes_spec.rb
new file mode 100644
index 00000000000..b51cb3055d5
--- /dev/null
+++ b/spec/requests/api/v3/notes_spec.rb
@@ -0,0 +1,432 @@
+require 'spec_helper'
+
+describe API::V3::Notes, api: true do
+ include ApiHelpers
+ let(:user) { create(:user) }
+ let!(:project) { create(:empty_project, :public, namespace: user.namespace) }
+ let!(:issue) { create(:issue, project: project, author: user) }
+ let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: user) }
+ let!(:snippet) { create(:project_snippet, project: project, author: user) }
+ let!(:issue_note) { create(:note, noteable: issue, project: project, author: user) }
+ let!(:merge_request_note) { create(:note, noteable: merge_request, project: project, author: user) }
+ let!(:snippet_note) { create(:note, noteable: snippet, project: project, author: user) }
+
+ # For testing the cross-reference of a private issue in a public issue
+ let(:private_user) { create(:user) }
+ let(:private_project) do
+ create(:empty_project, namespace: private_user.namespace).
+ tap { |p| p.team << [private_user, :master] }
+ end
+ let(:private_issue) { create(:issue, project: private_project) }
+
+ let(:ext_proj) { create(:empty_project, :public) }
+ let(:ext_issue) { create(:issue, project: ext_proj) }
+
+ let!(:cross_reference_note) do
+ create :note,
+ noteable: ext_issue, project: ext_proj,
+ note: "mentioned in issue #{private_issue.to_reference(ext_proj)}",
+ system: true
+ end
+
+ before { project.team << [user, :reporter] }
+
+ describe "GET /projects/:id/noteable/:noteable_id/notes" do
+ context "when noteable is an Issue" do
+ it "returns an array of issue notes" do
+ get v3_api("/projects/#{project.id}/issues/#{issue.id}/notes", user)
+
+ expect(response).to have_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.first['body']).to eq(issue_note.note)
+ expect(json_response.first['upvote']).to be_falsey
+ expect(json_response.first['downvote']).to be_falsey
+ end
+
+ it "returns a 404 error when issue id not found" do
+ get v3_api("/projects/#{project.id}/issues/12345/notes", user)
+
+ expect(response).to have_http_status(404)
+ end
+
+ context "and current user cannot view the notes" do
+ it "returns an empty array" do
+ get v3_api("/projects/#{ext_proj.id}/issues/#{ext_issue.id}/notes", user)
+
+ expect(response).to have_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response).to be_empty
+ end
+
+ context "and issue is confidential" do
+ before { ext_issue.update_attributes(confidential: true) }
+
+ it "returns 404" do
+ get v3_api("/projects/#{ext_proj.id}/issues/#{ext_issue.id}/notes", user)
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context "and current user can view the note" do
+ it "returns an empty array" do
+ get v3_api("/projects/#{ext_proj.id}/issues/#{ext_issue.id}/notes", private_user)
+
+ expect(response).to have_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.first['body']).to eq(cross_reference_note.note)
+ end
+ end
+ end
+ end
+
+ context "when noteable is a Snippet" do
+ it "returns an array of snippet notes" do
+ get v3_api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
+
+ expect(response).to have_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.first['body']).to eq(snippet_note.note)
+ end
+
+ it "returns a 404 error when snippet id not found" do
+ get v3_api("/projects/#{project.id}/snippets/42/notes", user)
+
+ expect(response).to have_http_status(404)
+ end
+
+ it "returns 404 when not authorized" do
+ get v3_api("/projects/#{project.id}/snippets/#{snippet.id}/notes", private_user)
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context "when noteable is a Merge Request" do
+ it "returns an array of merge_requests notes" do
+ get v3_api("/projects/#{project.id}/merge_requests/#{merge_request.id}/notes", user)
+
+ expect(response).to have_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.first['body']).to eq(merge_request_note.note)
+ end
+
+ it "returns a 404 error if merge request id not found" do
+ get v3_api("/projects/#{project.id}/merge_requests/4444/notes", user)
+
+ expect(response).to have_http_status(404)
+ end
+
+ it "returns 404 when not authorized" do
+ get v3_api("/projects/#{project.id}/merge_requests/4444/notes", private_user)
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+
+ describe "GET /projects/:id/noteable/:noteable_id/notes/:note_id" do
+ context "when noteable is an Issue" do
+ it "returns an issue note by id" do
+ get v3_api("/projects/#{project.id}/issues/#{issue.id}/notes/#{issue_note.id}", user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response['body']).to eq(issue_note.note)
+ end
+
+ it "returns a 404 error if issue note not found" do
+ get v3_api("/projects/#{project.id}/issues/#{issue.id}/notes/12345", user)
+
+ expect(response).to have_http_status(404)
+ end
+
+ context "and current user cannot view the note" do
+ it "returns a 404 error" do
+ get v3_api("/projects/#{ext_proj.id}/issues/#{ext_issue.id}/notes/#{cross_reference_note.id}", user)
+
+ expect(response).to have_http_status(404)
+ end
+
+ context "when issue is confidential" do
+ before { issue.update_attributes(confidential: true) }
+
+ it "returns 404" do
+ get v3_api("/projects/#{project.id}/issues/#{issue.id}/notes/#{issue_note.id}", private_user)
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context "and current user can view the note" do
+ it "returns an issue note by id" do
+ get v3_api("/projects/#{ext_proj.id}/issues/#{ext_issue.id}/notes/#{cross_reference_note.id}", private_user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response['body']).to eq(cross_reference_note.note)
+ end
+ end
+ end
+ end
+
+ context "when noteable is a Snippet" do
+ it "returns a snippet note by id" do
+ get v3_api("/projects/#{project.id}/snippets/#{snippet.id}/notes/#{snippet_note.id}", user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response['body']).to eq(snippet_note.note)
+ end
+
+ it "returns a 404 error if snippet note not found" do
+ get v3_api("/projects/#{project.id}/snippets/#{snippet.id}/notes/12345", user)
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+
+ describe "POST /projects/:id/noteable/:noteable_id/notes" do
+ context "when noteable is an Issue" do
+ it "creates a new issue note" do
+ post v3_api("/projects/#{project.id}/issues/#{issue.id}/notes", user), body: 'hi!'
+
+ expect(response).to have_http_status(201)
+ expect(json_response['body']).to eq('hi!')
+ expect(json_response['author']['username']).to eq(user.username)
+ end
+
+ it "returns a 400 bad request error if body not given" do
+ post v3_api("/projects/#{project.id}/issues/#{issue.id}/notes", user)
+
+ expect(response).to have_http_status(400)
+ end
+
+ it "returns a 401 unauthorized error if user not authenticated" do
+ post v3_api("/projects/#{project.id}/issues/#{issue.id}/notes"), body: 'hi!'
+
+ expect(response).to have_http_status(401)
+ end
+
+ context 'when an admin or owner makes the request' do
+ it 'accepts the creation date to be set' do
+ creation_time = 2.weeks.ago
+ post v3_api("/projects/#{project.id}/issues/#{issue.id}/notes", user),
+ body: 'hi!', created_at: creation_time
+
+ expect(response).to have_http_status(201)
+ expect(json_response['body']).to eq('hi!')
+ expect(json_response['author']['username']).to eq(user.username)
+ expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time)
+ end
+ end
+
+ context 'when the user is posting an award emoji on an issue created by someone else' do
+ let(:issue2) { create(:issue, project: project) }
+
+ it 'returns an award emoji' do
+ post v3_api("/projects/#{project.id}/issues/#{issue2.id}/notes", user), body: ':+1:'
+
+ expect(response).to have_http_status(201)
+ expect(json_response['awardable_id']).to eq issue2.id
+ end
+ end
+
+ context 'when the user is posting an award emoji on his/her own issue' do
+ it 'creates a new issue note' do
+ post v3_api("/projects/#{project.id}/issues/#{issue.id}/notes", user), body: ':+1:'
+
+ expect(response).to have_http_status(201)
+ expect(json_response['body']).to eq(':+1:')
+ end
+ end
+ end
+
+ context "when noteable is a Snippet" do
+ it "creates a new snippet note" do
+ post v3_api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user), body: 'hi!'
+
+ expect(response).to have_http_status(201)
+ expect(json_response['body']).to eq('hi!')
+ expect(json_response['author']['username']).to eq(user.username)
+ end
+
+ it "returns a 400 bad request error if body not given" do
+ post v3_api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
+
+ expect(response).to have_http_status(400)
+ end
+
+ it "returns a 401 unauthorized error if user not authenticated" do
+ post v3_api("/projects/#{project.id}/snippets/#{snippet.id}/notes"), body: 'hi!'
+
+ expect(response).to have_http_status(401)
+ end
+ end
+
+ context 'when user does not have access to read the noteable' do
+ it 'responds with 404' do
+ project = create(:empty_project, :private) { |p| p.add_guest(user) }
+ issue = create(:issue, :confidential, project: project)
+
+ post v3_api("/projects/#{project.id}/issues/#{issue.id}/notes", user),
+ body: 'Foo'
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'when user does not have access to create noteable' do
+ let(:private_issue) { create(:issue, project: create(:empty_project, :private)) }
+
+ ##
+ # We are posting to project user has access to, but we use issue id
+ # from a different project, see #15577
+ #
+ before do
+ post v3_api("/projects/#{project.id}/issues/#{private_issue.id}/notes", user),
+ body: 'Hi!'
+ end
+
+ it 'responds with resource not found error' do
+ expect(response.status).to eq 404
+ end
+
+ it 'does not create new note' do
+ expect(private_issue.notes.reload).to be_empty
+ end
+ end
+ end
+
+ describe "POST /projects/:id/noteable/:noteable_id/notes to test observer on create" do
+ it "creates an activity event when an issue note is created" do
+ expect(Event).to receive(:create)
+
+ post v3_api("/projects/#{project.id}/issues/#{issue.id}/notes", user), body: 'hi!'
+ end
+ end
+
+ describe 'PUT /projects/:id/noteable/:noteable_id/notes/:note_id' do
+ context 'when noteable is an Issue' do
+ it 'returns modified note' do
+ put v3_api("/projects/#{project.id}/issues/#{issue.id}/"\
+ "notes/#{issue_note.id}", user), body: 'Hello!'
+
+ expect(response).to have_http_status(200)
+ expect(json_response['body']).to eq('Hello!')
+ end
+
+ it 'returns a 404 error when note id not found' do
+ put v3_api("/projects/#{project.id}/issues/#{issue.id}/notes/12345", user),
+ body: 'Hello!'
+
+ expect(response).to have_http_status(404)
+ end
+
+ it 'returns a 400 bad request error if body not given' do
+ put v3_api("/projects/#{project.id}/issues/#{issue.id}/"\
+ "notes/#{issue_note.id}", user)
+
+ expect(response).to have_http_status(400)
+ end
+ end
+
+ context 'when noteable is a Snippet' do
+ it 'returns modified note' do
+ put v3_api("/projects/#{project.id}/snippets/#{snippet.id}/"\
+ "notes/#{snippet_note.id}", user), body: 'Hello!'
+
+ expect(response).to have_http_status(200)
+ expect(json_response['body']).to eq('Hello!')
+ end
+
+ it 'returns a 404 error when note id not found' do
+ put v3_api("/projects/#{project.id}/snippets/#{snippet.id}/"\
+ "notes/12345", user), body: "Hello!"
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'when noteable is a Merge Request' do
+ it 'returns modified note' do
+ put v3_api("/projects/#{project.id}/merge_requests/#{merge_request.id}/"\
+ "notes/#{merge_request_note.id}", user), body: 'Hello!'
+
+ expect(response).to have_http_status(200)
+ expect(json_response['body']).to eq('Hello!')
+ end
+
+ it 'returns a 404 error when note id not found' do
+ put v3_api("/projects/#{project.id}/merge_requests/#{merge_request.id}/"\
+ "notes/12345", user), body: "Hello!"
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+
+ describe 'DELETE /projects/:id/noteable/:noteable_id/notes/:note_id' do
+ context 'when noteable is an Issue' do
+ it 'deletes a note' do
+ delete v3_api("/projects/#{project.id}/issues/#{issue.id}/"\
+ "notes/#{issue_note.id}", user)
+
+ expect(response).to have_http_status(200)
+ # Check if note is really deleted
+ delete v3_api("/projects/#{project.id}/issues/#{issue.id}/"\
+ "notes/#{issue_note.id}", user)
+ expect(response).to have_http_status(404)
+ end
+
+ it 'returns a 404 error when note id not found' do
+ delete v3_api("/projects/#{project.id}/issues/#{issue.id}/notes/12345", user)
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'when noteable is a Snippet' do
+ it 'deletes a note' do
+ delete v3_api("/projects/#{project.id}/snippets/#{snippet.id}/"\
+ "notes/#{snippet_note.id}", user)
+
+ expect(response).to have_http_status(200)
+ # Check if note is really deleted
+ delete v3_api("/projects/#{project.id}/snippets/#{snippet.id}/"\
+ "notes/#{snippet_note.id}", user)
+ expect(response).to have_http_status(404)
+ end
+
+ it 'returns a 404 error when note id not found' do
+ delete v3_api("/projects/#{project.id}/snippets/#{snippet.id}/"\
+ "notes/12345", user)
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'when noteable is a Merge Request' do
+ it 'deletes a note' do
+ delete v3_api("/projects/#{project.id}/merge_requests/"\
+ "#{merge_request.id}/notes/#{merge_request_note.id}", user)
+
+ expect(response).to have_http_status(200)
+ # Check if note is really deleted
+ delete v3_api("/projects/#{project.id}/merge_requests/"\
+ "#{merge_request.id}/notes/#{merge_request_note.id}", user)
+ expect(response).to have_http_status(404)
+ end
+
+ it 'returns a 404 error when note id not found' do
+ delete v3_api("/projects/#{project.id}/merge_requests/"\
+ "#{merge_request.id}/notes/12345", user)
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/v3/project_snippets_spec.rb b/spec/requests/api/v3/project_snippets_spec.rb
index 3700477f0db..957a3bf97ef 100644
--- a/spec/requests/api/v3/project_snippets_spec.rb
+++ b/spec/requests/api/v3/project_snippets_spec.rb
@@ -85,43 +85,33 @@ describe API::ProjectSnippets, api: true do
allow_any_instance_of(AkismetService).to receive(:is_spam?).and_return(true)
end
- context 'when the project is private' do
- let(:private_project) { create(:project_empty_repo, :private) }
-
- context 'when the snippet is public' do
- it 'creates the snippet' do
- expect { create_snippet(private_project, visibility_level: Snippet::PUBLIC) }.
- to change { Snippet.count }.by(1)
- end
+ context 'when the snippet is private' do
+ it 'creates the snippet' do
+ expect { create_snippet(project, visibility_level: Snippet::PRIVATE) }.
+ to change { Snippet.count }.by(1)
end
end
- context 'when the project is public' do
- context 'when the snippet is private' do
- it 'creates the snippet' do
- expect { create_snippet(project, visibility_level: Snippet::PRIVATE) }.
- to change { Snippet.count }.by(1)
- end
+ context 'when the snippet is public' do
+ it 'rejects the shippet' do
+ expect { create_snippet(project, visibility_level: Snippet::PUBLIC) }.
+ not_to change { Snippet.count }
+
+ expect(response).to have_http_status(400)
+ expect(json_response['message']).to eq({ "error" => "Spam detected" })
end
- context 'when the snippet is public' do
- it 'rejects the shippet' do
- expect { create_snippet(project, visibility_level: Snippet::PUBLIC) }.
- not_to change { Snippet.count }
- expect(response).to have_http_status(400)
- end
-
- it 'creates a spam log' do
- expect { create_snippet(project, visibility_level: Snippet::PUBLIC) }.
- to change { SpamLog.count }.by(1)
- end
+ it 'creates a spam log' do
+ expect { create_snippet(project, visibility_level: Snippet::PUBLIC) }.
+ to change { SpamLog.count }.by(1)
end
end
end
end
describe 'PUT /projects/:project_id/snippets/:id/' do
- let(:snippet) { create(:project_snippet, author: admin) }
+ let(:visibility_level) { Snippet::PUBLIC }
+ let(:snippet) { create(:project_snippet, author: admin, visibility_level: visibility_level) }
it 'updates snippet' do
new_content = 'New content'
@@ -145,6 +135,56 @@ describe API::ProjectSnippets, api: true do
expect(response).to have_http_status(400)
end
+
+ context 'when the snippet is spam' do
+ def update_snippet(snippet_params = {})
+ put v3_api("/projects/#{snippet.project.id}/snippets/#{snippet.id}", admin), snippet_params
+ end
+
+ before do
+ allow_any_instance_of(AkismetService).to receive(:is_spam?).and_return(true)
+ end
+
+ context 'when the snippet is private' do
+ let(:visibility_level) { Snippet::PRIVATE }
+
+ it 'creates the snippet' do
+ expect { update_snippet(title: 'Foo') }.
+ to change { snippet.reload.title }.to('Foo')
+ end
+ end
+
+ context 'when the snippet is public' do
+ let(:visibility_level) { Snippet::PUBLIC }
+
+ it 'rejects the snippet' do
+ expect { update_snippet(title: 'Foo') }.
+ not_to change { snippet.reload.title }
+ end
+
+ it 'creates a spam log' do
+ expect { update_snippet(title: 'Foo') }.
+ to change { SpamLog.count }.by(1)
+ end
+ end
+
+ context 'when the private snippet is made public' do
+ let(:visibility_level) { Snippet::PRIVATE }
+
+ it 'rejects the snippet' do
+ expect { update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) }.
+ not_to change { snippet.reload.title }
+
+ expect(response).to have_http_status(400)
+ expect(json_response['message']).to eq({ "error" => "Spam detected" })
+ end
+
+ it 'creates a spam log' do
+ expect { update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) }.
+ to change { SpamLog.count }.by(1)
+ end
+ end
+ end
end
describe 'DELETE /projects/:project_id/snippets/:id/' do
diff --git a/spec/requests/api/v3/projects_spec.rb b/spec/requests/api/v3/projects_spec.rb
index 36d99d80e79..662be3f3531 100644
--- a/spec/requests/api/v3/projects_spec.rb
+++ b/spec/requests/api/v3/projects_spec.rb
@@ -84,7 +84,7 @@ describe API::V3::Projects, api: true do
context 'GET /projects?simple=true' do
it 'returns a simplified version of all the projects' do
- expected_keys = ["id", "http_url_to_repo", "web_url", "name", "name_with_namespace", "path", "path_with_namespace"]
+ expected_keys = %w(id http_url_to_repo web_url name name_with_namespace path path_with_namespace)
get v3_api('/projects?simple=true', user)
diff --git a/spec/requests/api/v3/templates_spec.rb b/spec/requests/api/v3/templates_spec.rb
index 4fd4e70bedd..f1e554b98cc 100644
--- a/spec/requests/api/v3/templates_spec.rb
+++ b/spec/requests/api/v3/templates_spec.rb
@@ -56,11 +56,11 @@ describe API::V3::Templates, api: true do
expect(json_response['popular']).to be true
expect(json_response['html_url']).to eq('http://choosealicense.com/licenses/mit/')
expect(json_response['source_url']).to eq('https://opensource.org/licenses/MIT')
- expect(json_response['description']).to include('A permissive license that is short and to the point.')
+ expect(json_response['description']).to include('A short and simple permissive license with conditions')
expect(json_response['conditions']).to eq(%w[include-copyright])
expect(json_response['permissions']).to eq(%w[commercial-use modifications distribution private-use])
expect(json_response['limitations']).to eq(%w[no-liability])
- expect(json_response['content']).to include('The MIT License (MIT)')
+ expect(json_response['content']).to include('MIT License')
end
end
@@ -70,7 +70,7 @@ describe API::V3::Templates, api: true do
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
- expect(json_response.size).to eq(15)
+ expect(json_response.size).to eq(12)
expect(json_response.map { |l| l['key'] }).to include('agpl-3.0')
end
@@ -98,7 +98,7 @@ describe API::V3::Templates, api: true do
let(:license_type) { 'mit' }
it 'returns the license text' do
- expect(json_response['content']).to include('The MIT License (MIT)')
+ expect(json_response['content']).to include('MIT License')
end
it 'replaces placeholder values' do
diff --git a/spec/requests/api/v3/todos_spec.rb b/spec/requests/api/v3/todos_spec.rb
new file mode 100644
index 00000000000..80fa697e949
--- /dev/null
+++ b/spec/requests/api/v3/todos_spec.rb
@@ -0,0 +1,73 @@
+require 'spec_helper'
+
+describe API::V3::Todos, api: true do
+ include ApiHelpers
+
+ let(:project_1) { create(:empty_project) }
+ let(:project_2) { create(:empty_project) }
+ let(:author_1) { create(:user) }
+ let(:author_2) { create(:user) }
+ let(:john_doe) { create(:user, username: 'john_doe') }
+ let!(:pending_1) { create(:todo, :mentioned, project: project_1, author: author_1, user: john_doe) }
+ let!(:pending_2) { create(:todo, project: project_2, author: author_2, user: john_doe) }
+ let!(:pending_3) { create(:todo, project: project_1, author: author_2, user: john_doe) }
+ let!(:done) { create(:todo, :done, project: project_1, author: author_1, user: john_doe) }
+
+ before do
+ project_1.team << [john_doe, :developer]
+ project_2.team << [john_doe, :developer]
+ end
+
+ describe 'DELETE /todos/:id' do
+ context 'when unauthenticated' do
+ it 'returns authentication error' do
+ delete v3_api("/todos/#{pending_1.id}")
+
+ expect(response.status).to eq(401)
+ end
+ end
+
+ context 'when authenticated' do
+ it 'marks a todo as done' do
+ delete v3_api("/todos/#{pending_1.id}", john_doe)
+
+ expect(response.status).to eq(200)
+ expect(pending_1.reload).to be_done
+ end
+
+ it 'updates todos cache' do
+ expect_any_instance_of(User).to receive(:update_todos_count_cache).and_call_original
+
+ delete v3_api("/todos/#{pending_1.id}", john_doe)
+ end
+ end
+ end
+
+ describe 'DELETE /todos' do
+ context 'when unauthenticated' do
+ it 'returns authentication error' do
+ delete v3_api('/todos')
+
+ expect(response.status).to eq(401)
+ end
+ end
+
+ context 'when authenticated' do
+ it 'marks all todos as done' do
+ delete v3_api('/todos', john_doe)
+
+ expect(response.status).to eq(200)
+ expect(response.body).to eq('3')
+ expect(pending_1.reload).to be_done
+ expect(pending_2.reload).to be_done
+ expect(pending_3.reload).to be_done
+ end
+
+ it 'updates todos cache' do
+ expect_any_instance_of(User).to receive(:update_todos_count_cache).and_call_original
+
+ delete v3_api("/todos", john_doe)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/v3/users_spec.rb b/spec/requests/api/v3/users_spec.rb
index 5020ef18a3a..17bbb0b53c1 100644
--- a/spec/requests/api/v3/users_spec.rb
+++ b/spec/requests/api/v3/users_spec.rb
@@ -186,4 +186,81 @@ describe API::V3::Users, api: true do
expect(response).to have_http_status(404)
end
end
+
+ describe 'GET /users/:id/events' do
+ let(:user) { create(:user) }
+ let(:project) { create(:empty_project) }
+ let(:note) { create(:note_on_issue, note: 'What an awesome day!', project: project) }
+
+ before do
+ project.add_user(user, :developer)
+ EventCreateService.new.leave_note(note, user)
+ end
+
+ context "as a user than cannot see the event's project" do
+ it 'returns no events' do
+ other_user = create(:user)
+
+ get api("/users/#{user.id}/events", other_user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_empty
+ end
+ end
+
+ context "as a user than can see the event's project" do
+ context 'joined event' do
+ it 'returns the "joined" event' do
+ get v3_api("/users/#{user.id}/events", user)
+
+ expect(response).to have_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+
+ comment_event = json_response.find { |e| e['action_name'] == 'commented on' }
+
+ expect(comment_event['project_id'].to_i).to eq(project.id)
+ expect(comment_event['author_username']).to eq(user.username)
+ expect(comment_event['note']['id']).to eq(note.id)
+ expect(comment_event['note']['body']).to eq('What an awesome day!')
+
+ joined_event = json_response.find { |e| e['action_name'] == 'joined' }
+
+ expect(joined_event['project_id'].to_i).to eq(project.id)
+ expect(joined_event['author_username']).to eq(user.username)
+ expect(joined_event['author']['name']).to eq(user.name)
+ end
+ end
+
+ context 'when there are multiple events from different projects' do
+ let(:second_note) { create(:note_on_issue, project: create(:empty_project)) }
+ let(:third_note) { create(:note_on_issue, project: project) }
+
+ before do
+ second_note.project.add_user(user, :developer)
+
+ [second_note, third_note].each do |note|
+ EventCreateService.new.leave_note(note, user)
+ end
+ end
+
+ it 'returns events in the correct order (from newest to oldest)' do
+ get v3_api("/users/#{user.id}/events", user)
+
+ comment_events = json_response.select { |e| e['action_name'] == 'commented on' }
+
+ expect(comment_events[0]['target_id']).to eq(third_note.id)
+ expect(comment_events[1]['target_id']).to eq(second_note.id)
+ expect(comment_events[2]['target_id']).to eq(note.id)
+ end
+ end
+ end
+
+ it 'returns a 404 error if not found' do
+ get v3_api('/users/42/events', user)
+
+ expect(response).to have_http_status(404)
+ expect(json_response['message']).to eq('404 User Not Found')
+ end
+ end
end
diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb
index f2385da8c13..c7284be09b7 100644
--- a/spec/requests/ci/api/builds_spec.rb
+++ b/spec/requests/ci/api/builds_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Ci::API::Builds do
include ApiHelpers
- let(:runner) { FactoryGirl.create(:ci_runner, tag_list: ["mysql", "ruby"]) }
+ let(:runner) { FactoryGirl.create(:ci_runner, tag_list: %w(mysql ruby)) }
let(:project) { FactoryGirl.create(:empty_project, shared_runners_enabled: false) }
let(:last_update) { nil }
diff --git a/spec/requests/ci/api/runners_spec.rb b/spec/requests/ci/api/runners_spec.rb
index bd55934d0c8..8719313783e 100644
--- a/spec/requests/ci/api/runners_spec.rb
+++ b/spec/requests/ci/api/runners_spec.rb
@@ -41,7 +41,7 @@ describe Ci::API::Runners do
it 'creates runner' do
expect(response).to have_http_status 201
- expect(Ci::Runner.first.tag_list.sort).to eq(["tag1", "tag2"])
+ expect(Ci::Runner.first.tag_list.sort).to eq(%w(tag1 tag2))
end
end
diff --git a/spec/requests/ci/api/triggers_spec.rb b/spec/requests/ci/api/triggers_spec.rb
index a30be767119..5321f8b134f 100644
--- a/spec/requests/ci/api/triggers_spec.rb
+++ b/spec/requests/ci/api/triggers_spec.rb
@@ -60,7 +60,8 @@ describe Ci::API::Triggers do
it 'validates variables to be a hash' do
post ci_api("/projects/#{project.ci_id}/refs/master/trigger"), options.merge(variables: 'value')
expect(response).to have_http_status(400)
- expect(json_response['message']).to eq('variables needs to be a hash')
+
+ expect(json_response['error']).to eq('variables is invalid')
end
it 'validates variables needs to be a map of key-valued strings' do
diff --git a/spec/requests/lfs_http_spec.rb b/spec/requests/lfs_http_spec.rb
index c0e7bab8199..5d495bc9e7d 100644
--- a/spec/requests/lfs_http_spec.rb
+++ b/spec/requests/lfs_http_spec.rb
@@ -25,11 +25,9 @@ describe 'Git LFS API and storage' do
{
'objects' => [
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
- 'size' => 1575078
- },
+ 'size' => 1575078 },
{ 'oid' => sample_oid,
- 'size' => sample_size
- }
+ 'size' => sample_size }
],
'operation' => 'upload'
}
@@ -53,11 +51,9 @@ describe 'Git LFS API and storage' do
{
'objects' => [
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
- 'size' => 1575078
- },
+ 'size' => 1575078 },
{ 'oid' => sample_oid,
- 'size' => sample_size
- }
+ 'size' => sample_size }
],
'operation' => 'upload'
}
@@ -374,11 +370,12 @@ describe 'Git LFS API and storage' do
describe 'download' do
let(:project) { create(:empty_project) }
let(:body) do
- { 'operation' => 'download',
+ {
+ 'operation' => 'download',
'objects' => [
{ 'oid' => sample_oid,
- 'size' => sample_size
- }]
+ 'size' => sample_size }
+ ]
}
end
@@ -393,16 +390,20 @@ describe 'Git LFS API and storage' do
end
it 'with href to download' do
- expect(json_response).to eq('objects' => [
- { 'oid' => sample_oid,
- 'size' => sample_size,
- 'actions' => {
- 'download' => {
- 'href' => "#{project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}",
- 'header' => { 'Authorization' => authorization }
+ expect(json_response).to eq({
+ 'objects' => [
+ {
+ 'oid' => sample_oid,
+ 'size' => sample_size,
+ 'actions' => {
+ 'download' => {
+ 'href' => "#{project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}",
+ 'header' => { 'Authorization' => authorization }
+ }
}
}
- }])
+ ]
+ })
end
end
@@ -417,24 +418,29 @@ describe 'Git LFS API and storage' do
end
it 'with href to download' do
- expect(json_response).to eq('objects' => [
- { 'oid' => sample_oid,
- 'size' => sample_size,
- 'error' => {
- 'code' => 404,
- 'message' => "Object does not exist on the server or you don't have permissions to access it",
+ expect(json_response).to eq({
+ 'objects' => [
+ {
+ 'oid' => sample_oid,
+ 'size' => sample_size,
+ 'error' => {
+ 'code' => 404,
+ 'message' => "Object does not exist on the server or you don't have permissions to access it",
+ }
}
- }])
+ ]
+ })
end
end
context 'when downloading a lfs object that does not exist' do
let(:body) do
- { 'operation' => 'download',
+ {
+ 'operation' => 'download',
'objects' => [
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
- 'size' => 1575078
- }]
+ 'size' => 1575078 }
+ ]
}
end
@@ -443,27 +449,30 @@ describe 'Git LFS API and storage' do
end
it 'with an 404 for specific object' do
- expect(json_response).to eq('objects' => [
- { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
- 'size' => 1575078,
- 'error' => {
- 'code' => 404,
- 'message' => "Object does not exist on the server or you don't have permissions to access it",
+ expect(json_response).to eq({
+ 'objects' => [
+ {
+ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
+ 'size' => 1575078,
+ 'error' => {
+ 'code' => 404,
+ 'message' => "Object does not exist on the server or you don't have permissions to access it",
+ }
}
- }])
+ ]
+ })
end
end
context 'when downloading one new and one existing lfs object' do
let(:body) do
- { 'operation' => 'download',
+ {
+ 'operation' => 'download',
'objects' => [
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
- 'size' => 1575078
- },
+ 'size' => 1575078 },
{ 'oid' => sample_oid,
- 'size' => sample_size
- }
+ 'size' => sample_size }
]
}
end
@@ -477,23 +486,28 @@ describe 'Git LFS API and storage' do
end
it 'responds with upload hypermedia link for the new object' do
- expect(json_response).to eq('objects' => [
- { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
- 'size' => 1575078,
- 'error' => {
- 'code' => 404,
- 'message' => "Object does not exist on the server or you don't have permissions to access it",
- }
- },
- { 'oid' => sample_oid,
- 'size' => sample_size,
- 'actions' => {
- 'download' => {
- 'href' => "#{project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}",
- 'header' => { 'Authorization' => authorization }
+ expect(json_response).to eq({
+ 'objects' => [
+ {
+ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
+ 'size' => 1575078,
+ 'error' => {
+ 'code' => 404,
+ 'message' => "Object does not exist on the server or you don't have permissions to access it",
+ }
+ },
+ {
+ 'oid' => sample_oid,
+ 'size' => sample_size,
+ 'actions' => {
+ 'download' => {
+ 'href' => "#{project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}",
+ 'header' => { 'Authorization' => authorization }
+ }
}
}
- }])
+ ]
+ })
end
end
end
@@ -597,17 +611,21 @@ describe 'Git LFS API and storage' do
end
it 'responds with status 200 and href to download' do
- expect(json_response).to eq('objects' => [
- { 'oid' => sample_oid,
- 'size' => sample_size,
- 'authenticated' => true,
- 'actions' => {
- 'download' => {
- 'href' => "#{project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}",
- 'header' => {}
+ expect(json_response).to eq({
+ 'objects' => [
+ {
+ 'oid' => sample_oid,
+ 'size' => sample_size,
+ 'authenticated' => true,
+ 'actions' => {
+ 'download' => {
+ 'href' => "#{project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}",
+ 'header' => {}
+ }
}
}
- }])
+ ]
+ })
end
end
@@ -626,11 +644,12 @@ describe 'Git LFS API and storage' do
describe 'upload' do
let(:project) { create(:project, :public) }
let(:body) do
- { 'operation' => 'upload',
+ {
+ 'operation' => 'upload',
'objects' => [
{ 'oid' => sample_oid,
- 'size' => sample_size
- }]
+ 'size' => sample_size }
+ ]
}
end
@@ -665,11 +684,12 @@ describe 'Git LFS API and storage' do
context 'when pushing a lfs object that does not exist' do
let(:body) do
- { 'operation' => 'upload',
+ {
+ 'operation' => 'upload',
'objects' => [
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
- 'size' => 1575078
- }]
+ 'size' => 1575078 }
+ ]
}
end
@@ -688,14 +708,13 @@ describe 'Git LFS API and storage' do
context 'when pushing one new and one existing lfs object' do
let(:body) do
- { 'operation' => 'upload',
+ {
+ 'operation' => 'upload',
'objects' => [
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
- 'size' => 1575078
- },
+ 'size' => 1575078 },
{ 'oid' => sample_oid,
- 'size' => sample_size
- }
+ 'size' => sample_size }
]
}
end
@@ -789,11 +808,12 @@ describe 'Git LFS API and storage' do
let(:project) { create(:empty_project) }
let(:authorization) { authorize_user }
let(:body) do
- { 'operation' => 'other',
+ {
+ 'operation' => 'other',
'objects' => [
{ 'oid' => sample_oid,
- 'size' => sample_size
- }]
+ 'size' => sample_size }
+ ]
}
end