3 describe Gitlab::API do
5 before(:each) { enable_observers }
7 let(:user) { create(:user) }
8 let(:user2) { create(:user) }
9 let(:user3) { create(:user) }
10 let(:admin) { create(:admin) }
11 let!(:project) { create(:project_with_code, creator_id: user.id) }
12 let!(:hook) { create(:project_hook, project: project, url: "http://example.com") }
13 let!(:snippet) { create(:snippet, author: user, project: project, title: 'example') }
14 let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) }
15 let!(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) }
17 before { project.team << [user, :reporter] }
19 describe "GET /projects" do
20 context "when unauthenticated" do
21 it "should return authentication error" do
23 response.status.should == 401
27 context "when authenticated" do
28 it "should return an array of projects" do
29 get api("/projects", user)
30 response.status.should == 200
31 json_response.should be_an Array
32 json_response.first['name'].should == project.name
33 json_response.first['owner']['email'].should == user.email
38 describe "POST /projects" do
39 context "maximum number of projects reached" do
41 (1..user2.projects_limit).each do |project|
42 post api("/projects", user2), name: "foo#{project}"
46 it "should not create new project" do
48 post api("/projects", user2), name: 'foo'
49 }.to change {Project.count}.by(0)
53 it "should create new project without path" do
54 expect { post api("/projects", user), name: 'foo' }.to change {Project.count}.by(1)
57 it "should not create new project without name" do
58 expect { post api("/projects", user) }.to_not change {Project.count}
61 it "should return a 400 error if name not given" do
62 post api("/projects", user)
63 response.status.should == 400
66 it "should create last project before reaching project limit" do
67 (1..user2.projects_limit-1).each { |p| post api("/projects", user2), name: "foo#{p}" }
68 post api("/projects", user2), name: "foo"
69 response.status.should == 201
72 it "should respond with 201 on success" do
73 post api("/projects", user), name: 'foo'
74 response.status.should == 201
77 it "should respond with 400 if name is not given" do
78 post api("/projects", user)
79 response.status.should == 400
82 it "should return a 403 error if project limit reached" do
83 (1..user.projects_limit).each do |p|
84 post api("/projects", user), name: "foo#{p}"
86 post api("/projects", user), name: 'bar'
87 response.status.should == 403
90 it "should assign attributes to project" do
91 project = attributes_for(:project, {
92 description: Faker::Lorem.sentence,
93 default_branch: 'stable',
94 issues_enabled: false,
96 merge_requests_enabled: false,
100 post api("/projects", user), project
102 project.each_pair do |k,v|
104 json_response[k.to_s].should == v
109 describe "POST /projects/user/:id" do
112 it "should create new project without path" do
113 expect { post api("/projects/user/#{user.id}", admin), name: 'foo' }.to change {Project.count}.by(1)
116 it "should not create new project without name" do
117 expect { post api("/projects/user/#{user.id}", admin) }.to_not change {Project.count}
120 it "should respond with 201 on success" do
121 post api("/projects/user/#{user.id}", admin), name: 'foo'
122 response.status.should == 201
125 it "should respond with 404 on failure" do
126 post api("/projects/user/#{user.id}", admin)
127 response.status.should == 404
130 it "should assign attributes to project" do
131 project = attributes_for(:project, {
132 description: Faker::Lorem.sentence,
133 default_branch: 'stable',
134 issues_enabled: false,
136 merge_requests_enabled: false,
140 post api("/projects/user/#{user.id}", admin), project
142 project.each_pair do |k,v|
144 json_response[k.to_s].should == v
149 describe "GET /projects/:id" do
150 it "should return a project by id" do
151 get api("/projects/#{project.id}", user)
152 response.status.should == 200
153 json_response['name'].should == project.name
154 json_response['owner']['email'].should == user.email
157 it "should return a project by path name" do
158 get api("/projects/#{project.id}", user)
159 response.status.should == 200
160 json_response['name'].should == project.name
163 it "should return a 404 error if not found" do
164 get api("/projects/42", user)
165 response.status.should == 404
166 json_response['message'].should == '404 Not Found'
169 it "should return a 404 error if user is not a member" do
170 other_user = create(:user)
171 get api("/projects/#{project.id}", other_user)
172 response.status.should == 404
176 describe "GET /projects/:id/repository/branches" do
177 it "should return an array of project branches" do
178 get api("/projects/#{project.id}/repository/branches", user)
179 response.status.should == 200
180 json_response.should be_an Array
181 json_response.first['name'].should == project.repo.heads.sort_by(&:name).first.name
185 describe "GET /projects/:id/repository/branches/:branch" do
186 it "should return the branch information for a single branch" do
187 get api("/projects/#{project.id}/repository/branches/new_design", user)
188 response.status.should == 200
190 json_response['name'].should == 'new_design'
191 json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1'
192 json_response['protected'].should == false
195 it "should return a 404 error if branch is not available" do
196 get api("/projects/#{project.id}/repository/branches/unknown", user)
197 response.status.should == 404
201 describe "PUT /projects/:id/repository/branches/:branch/protect" do
202 it "should protect a single branch" do
203 put api("/projects/#{project.id}/repository/branches/new_design/protect", user)
204 response.status.should == 200
206 json_response['name'].should == 'new_design'
207 json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1'
208 json_response['protected'].should == true
211 it "should return a 404 error if branch not found" do
212 put api("/projects/#{project.id}/repository/branches/unknown/protect", user)
213 response.status.should == 404
216 it "should return success when protect branch again" do
217 put api("/projects/#{project.id}/repository/branches/new_design/protect", user)
218 put api("/projects/#{project.id}/repository/branches/new_design/protect", user)
219 response.status.should == 200
223 describe "PUT /projects/:id/repository/branches/:branch/unprotect" do
224 it "should unprotect a single branch" do
225 put api("/projects/#{project.id}/repository/branches/new_design/unprotect", user)
226 response.status.should == 200
228 json_response['name'].should == 'new_design'
229 json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1'
230 json_response['protected'].should == false
233 it "should return success when unprotect branch" do
234 put api("/projects/#{project.id}/repository/branches/unknown/unprotect", user)
235 response.status.should == 404
238 it "should return success when unprotect branch again" do
239 put api("/projects/#{project.id}/repository/branches/new_design/unprotect", user)
240 put api("/projects/#{project.id}/repository/branches/new_design/unprotect", user)
241 response.status.should == 200
245 describe "GET /projects/:id/members" do
246 it "should return project team members" do
247 get api("/projects/#{project.id}/members", user)
248 response.status.should == 200
249 json_response.should be_an Array
250 json_response.count.should == 2
251 json_response.map { |u| u['email'] }.should include user.email
254 it "finds team members with query string" do
255 get api("/projects/#{project.id}/members", user), query: user.username
256 response.status.should == 200
257 json_response.should be_an Array
258 json_response.count.should == 1
259 json_response.first['email'].should == user.email
262 it "should return a 404 error if id not found" do
263 get api("/projects/9999/members", user)
264 response.status.should == 404
268 describe "GET /projects/:id/members/:user_id" do
269 it "should return project team member" do
270 get api("/projects/#{project.id}/members/#{user.id}", user)
271 response.status.should == 200
272 json_response['email'].should == user.email
273 json_response['access_level'].should == UsersProject::MASTER
276 it "should return a 404 error if user id not found" do
277 get api("/projects/#{project.id}/members/1234", user)
278 response.status.should == 404
282 describe "POST /projects/:id/members" do
283 it "should add user to project team" do
285 post api("/projects/#{project.id}/members", user), user_id: user2.id,
286 access_level: UsersProject::DEVELOPER
287 }.to change { UsersProject.count }.by(1)
289 response.status.should == 201
290 json_response['email'].should == user2.email
291 json_response['access_level'].should == UsersProject::DEVELOPER
294 it "should return a 201 status if user is already project member" do
295 post api("/projects/#{project.id}/members", user), user_id: user2.id,
296 access_level: UsersProject::DEVELOPER
298 post api("/projects/#{project.id}/members", user), user_id: user2.id,
299 access_level: UsersProject::DEVELOPER
300 }.not_to change { UsersProject.count }.by(1)
302 response.status.should == 201
303 json_response['email'].should == user2.email
304 json_response['access_level'].should == UsersProject::DEVELOPER
307 it "should return a 400 error when user id is not given" do
308 post api("/projects/#{project.id}/members", user), access_level: UsersProject::MASTER
309 response.status.should == 400
312 it "should return a 400 error when access level is not given" do
313 post api("/projects/#{project.id}/members", user), user_id: user2.id
314 response.status.should == 400
317 it "should return a 422 error when access level is not known" do
318 post api("/projects/#{project.id}/members", user), user_id: user2.id, access_level: 1234
319 response.status.should == 422
323 describe "PUT /projects/:id/members/:user_id" do
324 it "should update project team member" do
325 put api("/projects/#{project.id}/members/#{user3.id}", user), access_level: UsersProject::MASTER
326 response.status.should == 200
327 json_response['email'].should == user3.email
328 json_response['access_level'].should == UsersProject::MASTER
331 it "should return a 404 error if user_id is not found" do
332 put api("/projects/#{project.id}/members/1234", user), access_level: UsersProject::MASTER
333 response.status.should == 404
336 it "should return a 400 error when access level is not given" do
337 put api("/projects/#{project.id}/members/#{user3.id}", user)
338 response.status.should == 400
341 it "should return a 422 error when access level is not known" do
342 put api("/projects/#{project.id}/members/#{user3.id}", user), access_level: 123
343 response.status.should == 422
347 describe "DELETE /projects/:id/members/:user_id" do
348 it "should remove user from project team" do
350 delete api("/projects/#{project.id}/members/#{user3.id}", user)
351 }.to change { UsersProject.count }.by(-1)
354 it "should return 200 if team member is not part of a project" do
355 delete api("/projects/#{project.id}/members/#{user3.id}", user)
357 delete api("/projects/#{project.id}/members/#{user3.id}", user)
358 }.to_not change { UsersProject.count }.by(1)
361 it "should return 200 if team member already removed" do
362 delete api("/projects/#{project.id}/members/#{user3.id}", user)
363 delete api("/projects/#{project.id}/members/#{user3.id}", user)
364 response.status.should == 200
368 describe "DELETE /projects/:id/members/:user_id" do
369 it "should return 200 OK when the user was not member" do
371 delete api("/projects/#{project.id}/members/1000000", user)
372 }.to change { UsersProject.count }.by(0)
373 response.status.should == 200
374 json_response['message'].should == "Access revoked"
375 json_response['id'].should == 1000000
379 describe "GET /projects/:id/hooks" do
380 context "authorized user" do
381 it "should return project hooks" do
382 get api("/projects/#{project.id}/hooks", user)
383 response.status.should == 200
385 json_response.should be_an Array
386 json_response.count.should == 1
387 json_response.first['url'].should == "http://example.com"
391 context "unauthorized user" do
392 it "should not access project hooks" do
393 get api("/projects/#{project.id}/hooks", user3)
394 response.status.should == 403
399 describe "GET /projects/:id/hooks/:hook_id" do
400 context "authorized user" do
401 it "should return a project hook" do
402 get api("/projects/#{project.id}/hooks/#{hook.id}", user)
403 response.status.should == 200
404 json_response['url'].should == hook.url
407 it "should return a 404 error if hook id is not available" do
408 get api("/projects/#{project.id}/hooks/1234", user)
409 response.status.should == 404
413 context "unauthorized user" do
414 it "should not access an existing hook" do
415 get api("/projects/#{project.id}/hooks/#{hook.id}", user3)
416 response.status.should == 403
420 it "should return a 404 error if hook id is not available" do
421 get api("/projects/#{project.id}/hooks/1234", user)
422 response.status.should == 404
426 describe "POST /projects/:id/hooks" do
427 it "should add hook to project" do
429 post api("/projects/#{project.id}/hooks", user),
430 url: "http://example.com"
431 }.to change {project.hooks.count}.by(1)
432 response.status.should == 201
435 it "should return a 400 error if url not given" do
436 post api("/projects/#{project.id}/hooks", user)
437 response.status.should == 400
440 it "should return a 422 error if url not valid" do
441 post api("/projects/#{project.id}/hooks", user), "url" => "ftp://example.com"
442 response.status.should == 422
446 describe "PUT /projects/:id/hooks/:hook_id" do
447 it "should update an existing project hook" do
448 put api("/projects/#{project.id}/hooks/#{hook.id}", user),
449 url: 'http://example.org'
450 response.status.should == 200
451 json_response['url'].should == 'http://example.org'
454 it "should return 404 error if hook id not found" do
455 put api("/projects/#{project.id}/hooks/1234", user), url: 'http://example.org'
456 response.status.should == 404
459 it "should return 400 error if url is not given" do
460 put api("/projects/#{project.id}/hooks/#{hook.id}", user)
461 response.status.should == 400
464 it "should return a 422 error if url is not valid" do
465 put api("/projects/#{project.id}/hooks/#{hook.id}", user), url: 'ftp://example.com'
466 response.status.should == 422
470 describe "DELETE /projects/:id/hooks/:hook_id" do
471 it "should delete hook from project" do
473 delete api("/projects/#{project.id}/hooks/#{hook.id}", user)
474 }.to change {project.hooks.count}.by(-1)
475 response.status.should == 200
478 it "should return success when deleting hook" do
479 delete api("/projects/#{project.id}/hooks/#{hook.id}", user)
480 response.status.should == 200
483 it "should return success when deleting non existent hook" do
484 delete api("/projects/#{project.id}/hooks/42", user)
485 response.status.should == 200
488 it "should return a 400 error if hook id not given" do
489 delete api("/projects/#{project.id}/hooks", user)
490 response.status.should == 400
494 describe "GET /projects/:id/repository/tags" do
495 it "should return an array of project tags" do
496 get api("/projects/#{project.id}/repository/tags", user)
497 response.status.should == 200
498 json_response.should be_an Array
499 json_response.first['name'].should == project.repo.tags.sort_by(&:name).reverse.first.name
503 describe "GET /projects/:id/repository/commits" do
504 context "authorized user" do
505 before { project.team << [user2, :reporter] }
507 it "should return project commits" do
508 get api("/projects/#{project.id}/repository/commits", user)
509 response.status.should == 200
511 json_response.should be_an Array
512 json_response.first['id'].should == project.repository.commit.id
516 context "unauthorized user" do
517 it "should not return project commits" do
518 get api("/projects/#{project.id}/repository/commits")
519 response.status.should == 401
524 describe "GET /projects/:id/snippets" do
525 it "should return an array of project snippets" do
526 get api("/projects/#{project.id}/snippets", user)
527 response.status.should == 200
528 json_response.should be_an Array
529 json_response.first['title'].should == snippet.title
533 describe "GET /projects/:id/snippets/:snippet_id" do
534 it "should return a project snippet" do
535 get api("/projects/#{project.id}/snippets/#{snippet.id}", user)
536 response.status.should == 200
537 json_response['title'].should == snippet.title
540 it "should return a 404 error if snippet id not found" do
541 get api("/projects/#{project.id}/snippets/1234", user)
542 response.status.should == 404
546 describe "POST /projects/:id/snippets" do
547 it "should create a new project snippet" do
548 post api("/projects/#{project.id}/snippets", user),
549 title: 'api test', file_name: 'sample.rb', code: 'test'
550 response.status.should == 201
551 json_response['title'].should == 'api test'
554 it "should return a 400 error if title is not given" do
555 post api("/projects/#{project.id}/snippets", user),
556 file_name: 'sample.rb', code: 'test'
557 response.status.should == 400
560 it "should return a 400 error if file_name not given" do
561 post api("/projects/#{project.id}/snippets", user),
562 title: 'api test', code: 'test'
563 response.status.should == 400
566 it "should return a 400 error if code not given" do
567 post api("/projects/#{project.id}/snippets", user),
568 title: 'api test', file_name: 'sample.rb'
569 response.status.should == 400
573 describe "PUT /projects/:id/snippets/:shippet_id" do
574 it "should update an existing project snippet" do
575 put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
577 response.status.should == 200
578 json_response['title'].should == 'example'
579 snippet.reload.content.should == 'updated code'
582 it "should update an existing project snippet with new title" do
583 put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
584 title: 'other api test'
585 response.status.should == 200
586 json_response['title'].should == 'other api test'
590 describe "DELETE /projects/:id/snippets/:snippet_id" do
591 it "should delete existing project snippet" do
593 delete api("/projects/#{project.id}/snippets/#{snippet.id}", user)
594 }.to change { Snippet.count }.by(-1)
595 response.status.should == 200
598 it "should return success when deleting unknown snippet id" do
599 delete api("/projects/#{project.id}/snippets/1234", user)
600 response.status.should == 200
604 describe "GET /projects/:id/snippets/:snippet_id/raw" do
605 it "should get a raw project snippet" do
606 get api("/projects/#{project.id}/snippets/#{snippet.id}/raw", user)
607 response.status.should == 200
610 it "should return a 404 error if raw project snippet not found" do
611 get api("/projects/#{project.id}/snippets/5555/raw", user)
612 response.status.should == 404
616 describe "GET /projects/:id/repository/commits/:sha/blob" do
617 it "should get the raw file contents" do
618 get api("/projects/#{project.id}/repository/commits/master/blob?filepath=README.md", user)
619 response.status.should == 200
622 it "should return 404 for invalid branch_name" do
623 get api("/projects/#{project.id}/repository/commits/invalid_branch_name/blob?filepath=README.md", user)
624 response.status.should == 404
627 it "should return 404 for invalid file" do
628 get api("/projects/#{project.id}/repository/commits/master/blob?filepath=README.invalid", user)
629 response.status.should == 404
632 it "should return a 400 error if filepath is missing" do
633 get api("/projects/#{project.id}/repository/commits/master/blob", user)
634 response.status.should == 400
638 describe :deploy_keys do
639 let(:deploy_keys_project) { create(:deploy_keys_project, project: project) }
640 let(:deploy_key) { deploy_keys_project.deploy_key }
642 describe "GET /projects/:id/keys" do
643 before { deploy_key }
645 it "should return array of ssh keys" do
646 get api("/projects/#{project.id}/keys", user)
647 response.status.should == 200
648 json_response.should be_an Array
649 json_response.first['title'].should == deploy_key.title
653 describe "GET /projects/:id/keys/:key_id" do
654 it "should return a single key" do
655 get api("/projects/#{project.id}/keys/#{deploy_key.id}", user)
656 response.status.should == 200
657 json_response['title'].should == deploy_key.title
660 it "should return 404 Not Found with invalid ID" do
661 get api("/projects/#{project.id}/keys/404", user)
662 response.status.should == 404
666 describe "POST /projects/:id/keys" do
667 it "should not create an invalid ssh key" do
668 post api("/projects/#{project.id}/keys", user), { title: "invalid key" }
669 response.status.should == 404
672 it "should create new ssh key" do
673 key_attrs = attributes_for :key
675 post api("/projects/#{project.id}/keys", user), key_attrs
676 }.to change{ project.deploy_keys.count }.by(1)
680 describe "DELETE /projects/:id/keys/:key_id" do
681 before { deploy_key }
683 it "should delete existing key" do
685 delete api("/projects/#{project.id}/keys/#{deploy_key.id}", user)
686 }.to change{ project.deploy_keys.count }.by(-1)
689 it "should return 404 Not Found with invalid ID" do
690 delete api("/projects/#{project.id}/keys/404", user)
691 response.status.should == 404