diff options
Diffstat (limited to 'spec/requests')
91 files changed, 1285 insertions, 847 deletions
diff --git a/spec/requests/api/access_requests_spec.rb b/spec/requests/api/access_requests_spec.rb index 46edbd49b28..c8eacb38e6f 100644 --- a/spec/requests/api/access_requests_spec.rb +++ b/spec/requests/api/access_requests_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::AccessRequests, api: true do - include ApiHelpers - +describe API::AccessRequests do let(:master) { create(:user) } let(:developer) { create(:user) } let(:access_requester) { create(:user) } diff --git a/spec/requests/api/api_internal_helpers_spec.rb b/spec/requests/api/api_internal_helpers_spec.rb deleted file mode 100644 index f5265ea60ff..00000000000 --- a/spec/requests/api/api_internal_helpers_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -require 'spec_helper' - -describe ::API::Helpers::InternalHelpers do - include ::API::Helpers::InternalHelpers - - describe '.clean_project_path' do - project = 'namespace/project' - namespaced = File.join('namespace2', project) - - { - File.join(Dir.pwd, project) => project, - File.join(Dir.pwd, namespaced) => namespaced, - project => project, - namespaced => namespaced, - project + '.git' => project, - namespaced + '.git' => namespaced, - "/" + project => project, - "/" + namespaced => namespaced, - }.each do |project_path, expected| - context project_path do - # Relative and absolute storage paths, with and without trailing / - ['.', './', Dir.pwd, Dir.pwd + '/'].each do |storage_path| - context "storage path is #{storage_path}" do - subject { clean_project_path(project_path, [{ 'path' => storage_path }]) } - - it { is_expected.to eq(expected) } - end - end - end - end - end -end diff --git a/spec/requests/api/award_emoji_spec.rb b/spec/requests/api/award_emoji_spec.rb index f4d4a8a2cc7..bbdef0aeb1b 100644 --- a/spec/requests/api/award_emoji_spec.rb +++ b/spec/requests/api/award_emoji_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' -describe API::AwardEmoji, api: true do - include ApiHelpers +describe API::AwardEmoji do let(:user) { create(:user) } let!(:project) { create(:empty_project) } let(:issue) { create(:issue, project: project) } diff --git a/spec/requests/api/boards_spec.rb b/spec/requests/api/boards_spec.rb index 87c36639cd4..c27db716ef8 100644 --- a/spec/requests/api/boards_spec.rb +++ b/spec/requests/api/boards_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::Boards, api: true do - include ApiHelpers - +describe API::Boards do let(:user) { create(:user) } let(:user2) { create(:user) } let(:non_member) { create(:user) } diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb index a70f7beaae0..c64499fc8c0 100644 --- a/spec/requests/api/branches_spec.rb +++ b/spec/requests/api/branches_spec.rb @@ -1,9 +1,7 @@ require 'spec_helper' require 'mime/types' -describe API::Branches, api: true do - include ApiHelpers - +describe API::Branches do let(:user) { create(:user) } let!(:project) { create(:project, :repository, creator: user) } let!(:master) { create(:project_member, :master, user: user, project: project) } @@ -408,19 +406,6 @@ describe API::Branches, api: true do delete api("/projects/#{project.id}/repository/branches/foobar", user) expect(response).to have_http_status(404) end - - it "removes protected branch" do - create(:protected_branch, project: project, name: branch_name) - delete api("/projects/#{project.id}/repository/branches/#{branch_name}", user) - expect(response).to have_http_status(405) - expect(json_response['message']).to eq('Protected branch cant be removed') - end - - it "does not remove HEAD branch" do - delete api("/projects/#{project.id}/repository/branches/master", user) - expect(response).to have_http_status(405) - expect(json_response['message']).to eq('Cannot remove HEAD branch') - end end describe "DELETE /projects/:id/repository/merged_branches" do diff --git a/spec/requests/api/broadcast_messages_spec.rb b/spec/requests/api/broadcast_messages_spec.rb index 024fa66848c..67989689799 100644 --- a/spec/requests/api/broadcast_messages_spec.rb +++ b/spec/requests/api/broadcast_messages_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::BroadcastMessages, api: true do - include ApiHelpers - +describe API::BroadcastMessages do let(:user) { create(:user) } let(:admin) { create(:admin) } diff --git a/spec/requests/api/commit_statuses_spec.rb b/spec/requests/api/commit_statuses_spec.rb index d8b3cc041a5..1c163cee152 100644 --- a/spec/requests/api/commit_statuses_spec.rb +++ b/spec/requests/api/commit_statuses_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::CommitStatuses, api: true do - include ApiHelpers - +describe API::CommitStatuses do let!(:project) { create(:project, :repository) } let(:commit) { project.repository.commit } let(:guest) { create_user(:guest) } @@ -28,8 +26,8 @@ describe API::CommitStatuses, api: true do create(:commit_status, { pipeline: commit, ref: commit.ref }.merge(opts)) end - let!(:status1) { create_status(master, status: 'running') } - let!(:status2) { create_status(master, name: 'coverage', status: 'pending') } + let!(:status1) { create_status(master, status: 'running', retried: true) } + let!(:status2) { create_status(master, name: 'coverage', status: 'pending', retried: true) } let!(:status3) { create_status(develop, status: 'running', allow_failure: true) } let!(:status4) { create_status(master, name: 'coverage', status: 'success') } let!(:status5) { create_status(develop, name: 'coverage', status: 'success') } diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb index a10d876ffad..0b0e4c2b112 100644 --- a/spec/requests/api/commits_spec.rb +++ b/spec/requests/api/commits_spec.rb @@ -1,8 +1,7 @@ require 'spec_helper' require 'mime/types' -describe API::Commits, api: true do - include ApiHelpers +describe API::Commits do let(:user) { create(:user) } let(:user2) { create(:user) } let!(:project) { create(:project, :repository, creator: user, namespace: user.namespace) } @@ -599,8 +598,7 @@ describe API::Commits, api: true do post 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.') + expect(json_response['message']).to include('Sorry, we cannot cherry-pick this commit automatically.') end it 'returns 400 if you are not allowed to push to the target branch' do diff --git a/spec/requests/api/deploy_keys_spec.rb b/spec/requests/api/deploy_keys_spec.rb index 4f4b18cf0e0..843e9862b0c 100644 --- a/spec/requests/api/deploy_keys_spec.rb +++ b/spec/requests/api/deploy_keys_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::DeployKeys, api: true do - include ApiHelpers - +describe API::DeployKeys do let(:user) { create(:user) } let(:admin) { create(:admin) } let(:project) { create(:empty_project, creator_id: user.id) } @@ -108,6 +106,15 @@ describe API::DeployKeys, api: true do expect(response).to have_http_status(201) end + + it 'accepts can_push parameter' do + key_attrs = attributes_for :write_access_key + + post api("/projects/#{project.id}/deploy_keys", admin), key_attrs + + expect(response).to have_http_status(201) + expect(json_response['can_push']).to eq(true) + end end describe 'DELETE /projects/:id/deploy_keys/:key_id' do diff --git a/spec/requests/api/deployments_spec.rb b/spec/requests/api/deployments_spec.rb index e55575ffbda..90d78d060ca 100644 --- a/spec/requests/api/deployments_spec.rb +++ b/spec/requests/api/deployments_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::Deployments, api: true do - include ApiHelpers - +describe API::Deployments do let(:user) { create(:user) } let(:non_member) { create(:user) } let(:project) { deployment.environment.project } diff --git a/spec/requests/api/doorkeeper_access_spec.rb b/spec/requests/api/doorkeeper_access_spec.rb index f6fd567eca5..868fef65c1c 100644 --- a/spec/requests/api/doorkeeper_access_spec.rb +++ b/spec/requests/api/doorkeeper_access_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::API, api: true do - include ApiHelpers - +describe 'doorkeeper access' do let!(:user) { create(:user) } let!(:application) { Doorkeeper::Application.create!(name: "MyApp", redirect_uri: "https://app.com", owner: user) } let!(:token) { Doorkeeper::AccessToken.create! application_id: application.id, resource_owner_id: user.id, scopes: "api" } diff --git a/spec/requests/api/environments_spec.rb b/spec/requests/api/environments_spec.rb index b54ee8e8b85..aae03c84e1f 100644 --- a/spec/requests/api/environments_spec.rb +++ b/spec/requests/api/environments_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::Environments, api: true do - include ApiHelpers - +describe API::Environments do let(:user) { create(:user) } let(:non_member) { create(:user) } let(:project) { create(:empty_project, :private, namespace: user.namespace) } diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb index a7fad7f0bdb..deb2cac6869 100644 --- a/spec/requests/api/files_spec.rb +++ b/spec/requests/api/files_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' -describe API::Files, api: true do - include ApiHelpers +describe API::Files do let(:user) { create(:user) } let!(:project) { create(:project, :repository, namespace: user.namespace ) } let(:guest) { create(:user) { |u| project.add_guest(u) } } @@ -11,21 +10,8 @@ describe API::Files, api: true do 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("\.") } + let(:author_email) { 'user@example.org' } + let(:author_name) { 'John Doe' } before { project.team << [user, :developer] } @@ -218,7 +204,7 @@ describe API::Files, api: true do it "returns a 400 if editor fails to create file" do allow_any_instance_of(Repository).to receive(:create_file). - and_return(false) + and_raise(Repository::CommitError, 'Cannot create file') post api(route("any%2Etxt"), user), valid_params @@ -312,8 +298,8 @@ describe API::Files, api: true do 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(:delete_file).and_return(false) + it "returns a 400 if fails to delete file" do + allow_any_instance_of(Repository).to receive(:delete_file).and_raise(Repository::CommitError, 'Cannot delete file') delete api(route(file_path), user), valid_params @@ -343,7 +329,7 @@ describe API::Files, api: true do end let(:get_params) do { - ref: 'master', + ref: 'master' } end diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index 2545da7b1db..90b36374ded 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' -describe API::Groups, api: true do - include ApiHelpers +describe API::Groups do include UploadHelpers let(:user1) { create(:user, can_create_group: false) } @@ -74,7 +73,7 @@ describe API::Groups, api: true do storage_size: 702, repository_size: 123, lfs_objects_size: 234, - build_artifacts_size: 345, + build_artifacts_size: 345 }.stringify_keys exposed_attributes = attributes.dup exposed_attributes['job_artifacts_size'] = exposed_attributes.delete('build_artifacts_size') @@ -179,7 +178,7 @@ describe API::Groups, api: true do expect(json_response['path']).to eq(group1.path) expect(json_response['description']).to eq(group1.description) expect(json_response['visibility']).to eq(Gitlab::VisibilityLevel.string_level(group1.visibility_level)) - expect(json_response['avatar_url']).to eq(group1.avatar_url) + expect(json_response['avatar_url']).to eq(group1.avatar_url(only_path: false)) expect(json_response['web_url']).to eq(group1.web_url) expect(json_response['request_access_enabled']).to eq(group1.request_access_enabled) expect(json_response['full_name']).to eq(group1.full_name) diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb index 988a57a80ea..ed392acc607 100644 --- a/spec/requests/api/helpers_spec.rb +++ b/spec/requests/api/helpers_spec.rb @@ -1,8 +1,8 @@ require 'spec_helper' -describe API::Helpers, api: true do +describe API::Helpers do include API::APIGuard::HelperMethods - include API::Helpers + include described_class include SentryHelper let(:user) { create(:user) } @@ -427,6 +427,7 @@ describe API::Helpers, api: true do context 'current_user is nil' do before do expect_any_instance_of(self.class).to receive(:current_user).and_return(nil) + allow_any_instance_of(self.class).to receive(:initial_current_user).and_return(nil) end it 'returns a 401 response' do @@ -435,13 +436,38 @@ describe API::Helpers, api: true do end context 'current_user is present' do + let(:user) { build(:user) } + before do - expect_any_instance_of(self.class).to receive(:current_user).at_least(:once).and_return(User.new) + expect_any_instance_of(self.class).to receive(:current_user).at_least(:once).and_return(user) + expect_any_instance_of(self.class).to receive(:initial_current_user).and_return(user) end it 'does not raise an error' do expect { authenticate! }.not_to raise_error end end + + context 'current_user is blocked' do + let(:user) { build(:user, :blocked) } + + before do + expect_any_instance_of(self.class).to receive(:current_user).at_least(:once).and_return(user) + end + + it 'raises an error' do + expect_any_instance_of(self.class).to receive(:initial_current_user).and_return(user) + + expect { authenticate! }.to raise_error '401 - {"message"=>"401 Unauthorized"}' + end + + it "doesn't raise an error if an admin user is impersonating a blocked user (via sudo)" do + admin_user = build(:user, :admin) + + expect_any_instance_of(self.class).to receive(:initial_current_user).and_return(admin_user) + + expect { authenticate! }.not_to raise_error + end + end end end diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb index eed45d37444..2ceb4648ece 100644 --- a/spec/requests/api/internal_spec.rb +++ b/spec/requests/api/internal_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' -describe API::Internal, api: true do - include ApiHelpers +describe API::Internal do let(:user) { create(:user) } let(:key) { create(:key, user: user) } let(:project) { create(:project, :repository) } @@ -147,10 +146,31 @@ describe API::Internal, api: true do end end - describe "POST /internal/allowed" do + describe "POST /internal/allowed", :redis do context "access granted" do before do project.team << [user, :developer] + Timecop.freeze + end + + after do + Timecop.return + end + + context 'with env passed as a JSON' do + it 'sets env in RequestStore' do + expect(Gitlab::Git::Env).to receive(:set).with({ + 'GIT_OBJECT_DIRECTORY' => 'foo', + 'GIT_ALTERNATE_OBJECT_DIRECTORIES' => 'bar' + }) + + push(key, project.wiki, env: { + GIT_OBJECT_DIRECTORY: 'foo', + GIT_ALTERNATE_OBJECT_DIRECTORIES: 'bar' + }.to_json) + + expect(response).to have_http_status(200) + end end context "git push with project.wiki" do @@ -160,6 +180,8 @@ describe API::Internal, api: true do expect(response).to have_http_status(200) expect(json_response["status"]).to be_truthy expect(json_response["repository_path"]).to eq(project.wiki.repository.path_to_repo) + expect(json_response["gl_repository"]).to eq("wiki-#{project.id}") + expect(user).not_to have_an_activity_record end end @@ -170,6 +192,8 @@ describe API::Internal, api: true do expect(response).to have_http_status(200) expect(json_response["status"]).to be_truthy expect(json_response["repository_path"]).to eq(project.wiki.repository.path_to_repo) + expect(json_response["gl_repository"]).to eq("wiki-#{project.id}") + expect(user).to have_an_activity_record end end @@ -180,6 +204,8 @@ describe API::Internal, api: true do expect(response).to have_http_status(200) expect(json_response["status"]).to be_truthy expect(json_response["repository_path"]).to eq(project.repository.path_to_repo) + expect(json_response["gl_repository"]).to eq("project-#{project.id}") + expect(user).to have_an_activity_record end end @@ -190,6 +216,8 @@ describe API::Internal, api: true do expect(response).to have_http_status(200) expect(json_response["status"]).to be_truthy expect(json_response["repository_path"]).to eq(project.repository.path_to_repo) + expect(json_response["gl_repository"]).to eq("project-#{project.id}") + expect(user).not_to have_an_activity_record end context 'project as /namespace/project' do @@ -199,6 +227,7 @@ describe API::Internal, api: true do expect(response).to have_http_status(200) expect(json_response["status"]).to be_truthy expect(json_response["repository_path"]).to eq(project.repository.path_to_repo) + expect(json_response["gl_repository"]).to eq("project-#{project.id}") end end @@ -209,6 +238,7 @@ describe API::Internal, api: true do expect(response).to have_http_status(200) expect(json_response["status"]).to be_truthy expect(json_response["repository_path"]).to eq(project.repository.path_to_repo) + expect(json_response["gl_repository"]).to eq("project-#{project.id}") end end end @@ -225,6 +255,7 @@ describe API::Internal, api: true do expect(response).to have_http_status(200) expect(json_response["status"]).to be_falsey + expect(user).not_to have_an_activity_record end end @@ -234,6 +265,7 @@ describe API::Internal, api: true do expect(response).to have_http_status(200) expect(json_response["status"]).to be_falsey + expect(user).not_to have_an_activity_record end end end @@ -251,6 +283,7 @@ describe API::Internal, api: true do expect(response).to have_http_status(200) expect(json_response["status"]).to be_falsey + expect(user).not_to have_an_activity_record end end @@ -260,6 +293,7 @@ describe API::Internal, api: true do expect(response).to have_http_status(200) expect(json_response["status"]).to be_falsey + expect(user).not_to have_an_activity_record end end end @@ -416,18 +450,39 @@ describe API::Internal, api: true do expect(json_response).to eq([]) end + + context 'with a gl_repository parameter' do + let(:gl_repository) { "project-#{project.id}" } + + it 'returns link to create new merge request' do + get api("/internal/merge_request_urls?gl_repository=#{gl_repository}&changes=#{changes}"), secret_token: secret_token + + expect(json_response).to match [{ + "branch_name" => "new_branch", + "url" => "http://#{Gitlab.config.gitlab.host}/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch", + "new_merge_request" => true + }] + end + end end describe 'POST /notify_post_receive' do let(:valid_params) do - { repo_path: project.repository.path, secret_token: secret_token } + { project: project.repository.path, secret_token: secret_token } + end + + let(:valid_wiki_params) do + { project: project.wiki.repository.path, secret_token: secret_token } end before do allow(Gitlab.config.gitaly).to receive(:enabled).and_return(true) end - it "calls the Gitaly client if it's enabled" do + it "calls the Gitaly client with the project's repository" do + expect(Gitlab::GitalyClient::Notifications). + to receive(:new).with(gitlab_git_repository_with(path: project.repository.path)). + and_call_original expect_any_instance_of(Gitlab::GitalyClient::Notifications). to receive(:post_receive) @@ -436,6 +491,18 @@ describe API::Internal, api: true do expect(response).to have_http_status(200) end + it "calls the Gitaly client with the wiki's repository if it's a wiki" do + expect(Gitlab::GitalyClient::Notifications). + to receive(:new).with(gitlab_git_repository_with(path: project.wiki.repository.path)). + and_call_original + expect_any_instance_of(Gitlab::GitalyClient::Notifications). + to receive(:post_receive) + + post api("/internal/notify_post_receive"), valid_wiki_params + + expect(response).to have_http_status(200) + end + it "returns 500 if the gitaly call fails" do expect_any_instance_of(Gitlab::GitalyClient::Notifications). to receive(:post_receive).and_raise(GRPC::Unavailable) @@ -444,6 +511,40 @@ describe API::Internal, api: true do expect(response).to have_http_status(500) end + + context 'with a gl_repository parameter' do + let(:valid_params) do + { gl_repository: "project-#{project.id}", secret_token: secret_token } + end + + let(:valid_wiki_params) do + { gl_repository: "wiki-#{project.id}", secret_token: secret_token } + end + + it "calls the Gitaly client with the project's repository" do + expect(Gitlab::GitalyClient::Notifications). + to receive(:new).with(gitlab_git_repository_with(path: project.repository.path)). + and_call_original + expect_any_instance_of(Gitlab::GitalyClient::Notifications). + to receive(:post_receive) + + post api("/internal/notify_post_receive"), valid_params + + expect(response).to have_http_status(200) + end + + it "calls the Gitaly client with the wiki's repository if it's a wiki" do + expect(Gitlab::GitalyClient::Notifications). + to receive(:new).with(gitlab_git_repository_with(path: project.wiki.repository.path)). + and_call_original + expect_any_instance_of(Gitlab::GitalyClient::Notifications). + to receive(:post_receive) + + post api("/internal/notify_post_receive"), valid_wiki_params + + expect(response).to have_http_status(200) + end + end end def project_with_repo_path(path) @@ -463,7 +564,7 @@ describe API::Internal, api: true do ) end - def push(key, project, protocol = 'ssh') + def push(key, project, protocol = 'ssh', env: nil) post( api("/internal/allowed"), changes: 'd14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/master', @@ -471,7 +572,8 @@ describe API::Internal, api: true do project: project.repository.path_to_repo, action: 'git-receive-pack', secret_token: secret_token, - protocol: protocol + protocol: protocol, + env: env ) end diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 91d6fb83c0b..79cac721202 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -1,25 +1,29 @@ require 'spec_helper' -describe API::Issues, api: true do - include ApiHelpers +describe API::Issues do include EmailHelpers - let(:user) { create(:user) } + set(:user) { create(:user) } + set(:project) do + create(:empty_project, :public, creator_id: user.id, namespace: user.namespace) + end + let(:user2) { create(:user) } let(:non_member) { create(:user) } - let(:guest) { create(:user) } - let(:author) { create(:author) } - let(:assignee) { create(:assignee) } + set(:guest) { create(:user) } + set(:author) { create(:author) } + set(:assignee) { create(:assignee) } let(:admin) { create(:user, :admin) } - let!(:project) { create(:empty_project, :public, creator_id: user.id, namespace: user.namespace ) } + let(:issue_title) { 'foo' } + let(:issue_description) { 'closed' } let!(:closed_issue) do create :closed_issue, author: user, - assignee: user, + assignees: [user], project: project, state: :closed, milestone: milestone, - created_at: generate(:issue_created_at), + created_at: generate(:past_time), updated_at: 3.hours.ago end let!(:confidential_issue) do @@ -27,32 +31,34 @@ describe API::Issues, api: true do :confidential, project: project, author: author, - assignee: assignee, - created_at: generate(:issue_created_at), + assignees: [assignee], + created_at: generate(:past_time), updated_at: 2.hours.ago end let!(:issue) do create :issue, author: user, - assignee: user, + assignees: [user], project: project, milestone: milestone, - created_at: generate(:issue_created_at), - updated_at: 1.hour.ago + created_at: generate(:past_time), + updated_at: 1.hour.ago, + title: issue_title, + description: issue_description end - let!(:label) do + set(:label) do create(:label, title: 'label', color: '#FFAABB', project: project) end let!(:label_link) { create(:label_link, label: label, target: issue) } - let!(:milestone) { create(:milestone, title: '1.0.0', project: project) } - let!(:empty_milestone) do + set(:milestone) { create(:milestone, title: '1.0.0', project: project) } + set(:empty_milestone) do create(:milestone, title: '2.0.0', project: project) end let!(:note) { create(:note_on_issue, author: user, project: project, noteable: issue) } let(:no_milestone_title) { URI.escape(Milestone::None.title) } - before do + before(:all) do project.team << [user, :reporter] project.team << [guest, :guest] end @@ -61,60 +67,63 @@ describe API::Issues, api: true do context "when unauthenticated" do it "returns authentication error" do get api("/issues") + expect(response).to have_http_status(401) end end context "when authenticated" do + let(:first_issue) { json_response.first } + it "returns an array of issues" do get api("/issues", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + expect_paginated_array_response(size: 2) expect(json_response.first['title']).to eq(issue.title) expect(json_response.last).to have_key('web_url') end it 'returns an array of closed issues' do - get api('/issues?state=closed', user) + get api('/issues', user), state: :closed - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) - expect(json_response.first['id']).to eq(closed_issue.id) + expect_paginated_array_response(size: 1) + expect(first_issue['id']).to eq(closed_issue.id) end it 'returns an array of opened issues' do - get api('/issues?state=opened', user) + get api('/issues', user), state: :opened - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) - expect(json_response.first['id']).to eq(issue.id) + expect_paginated_array_response(size: 1) + expect(first_issue['id']).to eq(issue.id) end it 'returns an array of all issues' do - get api('/issues?state=all', user) + get api('/issues', user), state: :all - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(2) - expect(json_response.first['id']).to eq(issue.id) + expect_paginated_array_response(size: 2) + expect(first_issue['id']).to eq(issue.id) expect(json_response.second['id']).to eq(closed_issue.id) end + it 'returns issues matching given search string for title' do + get api("/issues", user), search: issue.title + + expect_paginated_array_response(size: 1) + expect(json_response.first['id']).to eq(issue.id) + end + + it 'returns issues matching given search string for description' do + get api("/issues", user), search: issue.description + + expect_paginated_array_response(size: 1) + expect(first_issue['id']).to eq(issue.id) + end + it 'returns an array of labeled issues' do - get api("/issues?labels=#{label.title}", user) + get api("/issues", user), labels: label.title - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) - expect(json_response.first['labels']).to eq([label.title]) + expect_paginated_array_response(size: 1) + expect(first_issue['labels']).to eq([label.title]) end it 'returns an array of labeled issues when all labels matches' do @@ -126,29 +135,20 @@ describe API::Issues, api: true do get api("/issues", user), labels: "#{label.title},#{label_b.title},#{label_c.title}" - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['labels']).to eq([label_c.title, label_b.title, label.title]) end it 'returns an empty array if no issue matches labels' do - get api('/issues?labels=foo,bar', user) + get api('/issues', user), labels: 'foo,bar' - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an array of labeled issues matching given state' do - get api("/issues?labels=#{label.title}&state=opened", user) + get api("/issues", user), labels: label.title, state: :opened - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['labels']).to eq([label.title]) expect(json_response.first['state']).to eq('opened') end @@ -156,47 +156,32 @@ describe API::Issues, api: true do it 'returns unlabeled issues for "No Label" label' do get api("/issues", user), labels: 'No Label' - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['labels']).to be_empty end it 'returns an empty array if no issue matches labels and state filters' do get api("/issues?labels=#{label.title}&state=closed", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an empty array if no issue matches milestone' do get api("/issues?milestone=#{empty_milestone.title}", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an empty array if milestone does not exist' do get api("/issues?milestone=foo", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an array of issues in given milestone' do get api("/issues?milestone=#{milestone.title}", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(2) + expect_paginated_array_response(size: 2) expect(json_response.first['id']).to eq(issue.id) expect(json_response.second['id']).to eq(closed_issue.id) end @@ -205,49 +190,36 @@ describe API::Issues, api: true do get api("/issues?milestone=#{milestone.title}"\ '&state=closed', user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['id']).to eq(closed_issue.id) end it 'returns an array of issues with no milestone' do get api("/issues?milestone=#{no_milestone_title}", author) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['id']).to eq(confidential_issue.id) end it 'returns an array of issues found by iids' do get api('/issues', user), iids: [closed_issue.iid] - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['id']).to eq(closed_issue.id) end it 'returns an empty array if iid does not exist' do get api("/issues", user), iids: [99999] - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'sorts by created_at descending by default' do get api('/issues', user) response_dates = json_response.map { |issue| issue['created_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 2) expect(response_dates).to eq(response_dates.sort.reverse) end @@ -255,9 +227,8 @@ describe API::Issues, api: true do get api('/issues?sort=asc', user) response_dates = json_response.map { |issue| issue['created_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 2) expect(response_dates).to eq(response_dates.sort) end @@ -265,9 +236,8 @@ describe API::Issues, api: true do get api('/issues?order_by=updated_at', user) response_dates = json_response.map { |issue| issue['updated_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 2) expect(response_dates).to eq(response_dates.sort.reverse) end @@ -275,9 +245,8 @@ describe API::Issues, api: true do get api('/issues?order_by=updated_at&sort=asc', user) response_dates = json_response.map { |issue| issue['updated_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 2) expect(response_dates).to eq(response_dates.sort) end @@ -296,7 +265,7 @@ describe API::Issues, api: true do let!(:group_closed_issue) do create :closed_issue, author: user, - assignee: user, + assignees: [user], project: group_project, state: :closed, milestone: group_milestone, @@ -307,16 +276,18 @@ describe API::Issues, api: true do :confidential, project: group_project, author: author, - assignee: assignee, + assignees: [assignee], updated_at: 2.hours.ago end let!(:group_issue) do create :issue, author: user, - assignee: user, + assignees: [user], project: group_project, milestone: group_milestone, - updated_at: 1.hour.ago + updated_at: 1.hour.ago, + title: issue_title, + description: issue_description end let!(:group_label) do create(:label, title: 'group_lbl', color: '#FFAABB', project: group_project) @@ -336,74 +307,65 @@ describe API::Issues, api: true do it 'returns all group issues (including opened and closed)' do get api(base_url, admin) - expect(response).to have_http_status(200) - expect(json_response).to be_an Array - expect(json_response.length).to eq(3) + expect_paginated_array_response(size: 3) end it 'returns group issues without confidential issues for non project members' do get api("#{base_url}?state=opened", non_member) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['title']).to eq(group_issue.title) end it 'returns group confidential issues for author' do get api("#{base_url}?state=opened", author) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(2) + expect_paginated_array_response(size: 2) end it 'returns group confidential issues for assignee' do get api("#{base_url}?state=opened", assignee) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(2) + expect_paginated_array_response(size: 2) end it 'returns group issues with confidential issues for project members' do get api("#{base_url}?state=opened", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(2) + expect_paginated_array_response(size: 2) end it 'returns group confidential issues for admin' do get api("#{base_url}?state=opened", admin) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(2) + expect_paginated_array_response(size: 2) end it 'returns an array of labeled group issues' do get api("#{base_url}?labels=#{group_label.title}", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['labels']).to eq([group_label.title]) end it 'returns an array of labeled group issues where all labels match' do get api("#{base_url}?labels=#{group_label.title},foo,bar", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) + end + + it 'returns issues matching given search string for title' do + get api("#{base_url}?search=#{group_issue.title}", user) + + expect_paginated_array_response(size: 1) + expect(json_response.first['id']).to eq(group_issue.id) + end + + it 'returns issues matching given search string for description' do + get api("#{base_url}?search=#{group_issue.description}", user) + + expect_paginated_array_response(size: 1) + expect(json_response.first['id']).to eq(group_issue.id) end it 'returns an array of labeled issues when all labels matches' do @@ -415,65 +377,45 @@ describe API::Issues, api: true do get api("#{base_url}", user), labels: "#{group_label.title},#{label_b.title},#{label_c.title}" - expect(response).to have_http_status(200) - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['labels']).to eq([label_c.title, label_b.title, group_label.title]) end it 'returns an array of issues found by iids' do get api(base_url, user), iids: [group_issue.iid] - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['id']).to eq(group_issue.id) end it 'returns an empty array if iid does not exist' do get api(base_url, user), iids: [99999] - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an empty array if no group issue matches labels' do get api("#{base_url}?labels=foo,bar", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an empty array if no issue matches milestone' do get api("#{base_url}?milestone=#{group_empty_milestone.title}", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an empty array if milestone does not exist' do get api("#{base_url}?milestone=foo", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an array of issues in given milestone' do get api("#{base_url}?state=opened&milestone=#{group_milestone.title}", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['id']).to eq(group_issue.id) end @@ -481,10 +423,7 @@ describe API::Issues, api: true do get api("#{base_url}?milestone=#{group_milestone.title}"\ '&state=closed', user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['id']).to eq(group_closed_issue.id) end @@ -492,9 +431,8 @@ describe API::Issues, api: true do get api("#{base_url}?milestone=#{no_milestone_title}", user) expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + + expect_paginated_array_response(size: 1) expect(json_response.first['id']).to eq(group_confidential_issue.id) end @@ -502,9 +440,8 @@ describe API::Issues, api: true do get api(base_url, user) response_dates = json_response.map { |issue| issue['created_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 3) expect(response_dates).to eq(response_dates.sort.reverse) end @@ -512,9 +449,8 @@ describe API::Issues, api: true do get api("#{base_url}?sort=asc", user) response_dates = json_response.map { |issue| issue['created_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 3) expect(response_dates).to eq(response_dates.sort) end @@ -522,9 +458,8 @@ describe API::Issues, api: true do get api("#{base_url}?order_by=updated_at", user) response_dates = json_response.map { |issue| issue['updated_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 3) expect(response_dates).to eq(response_dates.sort.reverse) end @@ -532,9 +467,8 @@ describe API::Issues, api: true do get api("#{base_url}?order_by=updated_at&sort=asc", user) response_dates = json_response.map { |issue| issue['updated_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 3) expect(response_dates).to eq(response_dates.sort) end end @@ -563,79 +497,55 @@ describe API::Issues, api: true do get api("/projects/#{restricted_project.id}/issues", non_member) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response).to eq([]) + expect_paginated_array_response(size: 0) end it 'returns project issues without confidential issues for non project members' do get api("#{base_url}/issues", non_member) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(2) + expect_paginated_array_response(size: 2) expect(json_response.first['title']).to eq(issue.title) end it 'returns project issues without confidential issues for project members with guest role' do get api("#{base_url}/issues", guest) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(2) + expect_paginated_array_response(size: 2) expect(json_response.first['title']).to eq(issue.title) end it 'returns project confidential issues for author' do get api("#{base_url}/issues", author) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(3) + expect_paginated_array_response(size: 3) expect(json_response.first['title']).to eq(issue.title) end it 'returns project confidential issues for assignee' do get api("#{base_url}/issues", assignee) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(3) + expect_paginated_array_response(size: 3) expect(json_response.first['title']).to eq(issue.title) end it 'returns project issues with confidential issues for project members' do get api("#{base_url}/issues", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(3) + expect_paginated_array_response(size: 3) expect(json_response.first['title']).to eq(issue.title) end it 'returns project confidential issues for admin' do get api("#{base_url}/issues", admin) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(3) + expect_paginated_array_response(size: 3) expect(json_response.first['title']).to eq(issue.title) end it 'returns an array of labeled project issues' do get api("#{base_url}/issues?labels=#{label.title}", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['labels']).to eq([label.title]) end @@ -648,74 +558,65 @@ describe API::Issues, api: true do get api("#{base_url}/issues", user), labels: "#{label.title},#{label_b.title},#{label_c.title}" - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['labels']).to eq([label_c.title, label_b.title, label.title]) end + it 'returns issues matching given search string for title' do + get api("#{base_url}/issues?search=#{issue.title}", user) + + expect_paginated_array_response(size: 1) + expect(json_response.first['id']).to eq(issue.id) + end + + it 'returns issues matching given search string for description' do + get api("#{base_url}/issues?search=#{issue.description}", user) + + expect_paginated_array_response(size: 1) + expect(json_response.first['id']).to eq(issue.id) + end + it 'returns an array of issues found by iids' do get api("#{base_url}/issues", user), iids: [issue.iid] - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['id']).to eq(issue.id) end it 'returns an empty array if iid does not exist' do get api("#{base_url}/issues", user), iids: [99999] - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an empty array if not all labels matches' do get api("#{base_url}/issues?labels=#{label.title},foo", user) - expect(response).to have_http_status(200) - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an empty array if no project issue matches labels' do get api("#{base_url}/issues?labels=foo,bar", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an empty array if no issue matches milestone' do get api("#{base_url}/issues?milestone=#{empty_milestone.title}", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an empty array if milestone does not exist' do get api("#{base_url}/issues?milestone=foo", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an array of issues in given milestone' do get api("#{base_url}/issues?milestone=#{milestone.title}", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(2) + expect_paginated_array_response(size: 2) expect(json_response.first['id']).to eq(issue.id) expect(json_response.second['id']).to eq(closed_issue.id) end @@ -723,20 +624,14 @@ describe API::Issues, api: true do it 'returns an array of issues matching state in milestone' do get api("#{base_url}/issues?milestone=#{milestone.title}&state=closed", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['id']).to eq(closed_issue.id) end it 'returns an array of issues with no milestone' do get api("#{base_url}/issues?milestone=#{no_milestone_title}", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['id']).to eq(confidential_issue.id) end @@ -744,9 +639,8 @@ describe API::Issues, api: true do get api("#{base_url}/issues", user) response_dates = json_response.map { |issue| issue['created_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 3) expect(response_dates).to eq(response_dates.sort.reverse) end @@ -754,9 +648,8 @@ describe API::Issues, api: true do get api("#{base_url}/issues?sort=asc", user) response_dates = json_response.map { |issue| issue['created_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 3) expect(response_dates).to eq(response_dates.sort) end @@ -764,9 +657,8 @@ describe API::Issues, api: true do get api("#{base_url}/issues?order_by=updated_at", user) response_dates = json_response.map { |issue| issue['updated_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 3) expect(response_dates).to eq(response_dates.sort.reverse) end @@ -774,9 +666,8 @@ describe API::Issues, api: true do get api("#{base_url}/issues?order_by=updated_at&sort=asc", user) response_dates = json_response.map { |issue| issue['updated_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 3) expect(response_dates).to eq(response_dates.sort) end end @@ -796,6 +687,7 @@ describe API::Issues, api: true do expect(json_response['updated_at']).to be_present expect(json_response['labels']).to eq(issue.label_names) expect(json_response['milestone']).to be_a Hash + expect(json_response['assignees']).to be_a Array expect(json_response['assignee']).to be_a Hash expect(json_response['author']).to be_a Hash expect(json_response['confidential']).to be_falsy @@ -868,15 +760,41 @@ describe API::Issues, api: true do end describe "POST /projects/:id/issues" do + context 'support for deprecated assignee_id' do + it 'creates a new project issue' do + post api("/projects/#{project.id}/issues", user), + title: 'new issue', assignee_id: user2.id + + expect(response).to have_http_status(201) + expect(json_response['title']).to eq('new issue') + expect(json_response['assignee']['name']).to eq(user2.name) + expect(json_response['assignees'].first['name']).to eq(user2.name) + end + end + + context 'CE restrictions' do + it 'creates a new project issue with no more than one assignee' do + post api("/projects/#{project.id}/issues", user), + title: 'new issue', assignee_ids: [user2.id, guest.id] + + expect(response).to have_http_status(201) + expect(json_response['title']).to eq('new issue') + expect(json_response['assignees'].count).to eq(1) + end + end + it 'creates a new project issue' do post api("/projects/#{project.id}/issues", user), - title: 'new issue', labels: 'label, label2' + title: 'new issue', labels: 'label, label2', weight: 3, + assignee_ids: [user2.id] 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(%w(label label2)) expect(json_response['confidential']).to be_falsy + expect(json_response['assignee']['name']).to eq(user2.name) + expect(json_response['assignees'].first['name']).to eq(user2.name) end it 'creates a new confidential project issue' do @@ -953,7 +871,7 @@ describe API::Issues, api: true do end context 'resolving discussions' do - let(:discussion) { Discussion.for_diff_notes([create(:diff_note_on_merge_request)]).first } + let(:discussion) { create(:diff_note_on_merge_request).to_discussion } let(:merge_request) { discussion.noteable } let(:project) { merge_request.source_project } @@ -1166,6 +1084,57 @@ describe API::Issues, api: true do end end + describe 'PUT /projects/:id/issues/:issue_iid to update assignee' do + context 'support for deprecated assignee_id' do + it 'removes assignee' do + put api("/projects/#{project.id}/issues/#{issue.iid}", user), + assignee_id: 0 + + expect(response).to have_http_status(200) + + expect(json_response['assignee']).to be_nil + end + + it 'updates an issue with new assignee' do + put api("/projects/#{project.id}/issues/#{issue.iid}", user), + assignee_id: user2.id + + expect(response).to have_http_status(200) + + expect(json_response['assignee']['name']).to eq(user2.name) + end + end + + it 'removes assignee' do + put api("/projects/#{project.id}/issues/#{issue.iid}", user), + assignee_ids: [0] + + expect(response).to have_http_status(200) + + expect(json_response['assignees']).to be_empty + end + + it 'updates an issue with new assignee' do + put api("/projects/#{project.id}/issues/#{issue.iid}", user), + assignee_ids: [user2.id] + + expect(response).to have_http_status(200) + + expect(json_response['assignees'].first['name']).to eq(user2.name) + end + + context 'CE restrictions' do + it 'updates an issue with several assignees but only one has been applied' do + put api("/projects/#{project.id}/issues/#{issue.iid}", user), + assignee_ids: [user2.id, guest.id] + + expect(response).to have_http_status(200) + + expect(json_response['assignees'].size).to eq(1) + end + end + end + describe 'PUT /projects/:id/issues/:issue_iid to update labels' do let!(:label) { create(:label, title: 'dummy', project: project) } let!(:label_link) { create(:label_link, label: label, target: issue) } @@ -1457,4 +1426,46 @@ describe API::Issues, api: true do include_examples 'time tracking endpoints', 'issue' end + + describe 'GET :id/issues/:issue_iid/closed_by' do + let(:merge_request) do + create(:merge_request, + :simple, + author: user, + source_project: project, + target_project: project, + description: "closes #{issue.to_reference}") + end + + before do + create(:merge_requests_closing_issues, issue: issue, merge_request: merge_request) + end + + it 'returns merge requests that will close issue on merge' do + get api("/projects/#{project.id}/issues/#{issue.iid}/closed_by", user) + + expect_paginated_array_response(size: 1) + end + + context 'when no merge requests will close issue' do + it 'returns empty array' do + get api("/projects/#{project.id}/issues/#{closed_issue.iid}/closed_by", user) + + expect_paginated_array_response(size: 0) + end + end + + it "returns 404 when issue doesn't exists" do + get api("/projects/#{project.id}/issues/9999/closed_by", user) + + expect(response).to have_http_status(404) + end + end + + def expect_paginated_array_response(size: nil) + expect(response).to have_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.length).to eq(size) if size + end end diff --git a/spec/requests/api/jobs_spec.rb b/spec/requests/api/jobs_spec.rb index 9450701064b..e5e5872dc1f 100644 --- a/spec/requests/api/jobs_spec.rb +++ b/spec/requests/api/jobs_spec.rb @@ -1,16 +1,26 @@ require 'spec_helper' -describe API::Jobs, api: true do - include ApiHelpers +describe API::Jobs, :api do + let!(:project) do + create(:project, :repository, public_builds: false) + end + + let!(:pipeline) do + create(:ci_empty_pipeline, project: project, + sha: project.commit.id, + ref: project.default_branch) + end + + let!(:build) { create(:ci_build, pipeline: pipeline) } let(:user) { create(:user) } let(:api_user) { user } - let!(:project) { create(:project, :repository, creator: user, public_builds: false) } - let!(:developer) { create(:project_member, :developer, user: user, project: project) } - let(:reporter) { create(:project_member, :reporter, project: project) } - let(:guest) { create(:project_member, :guest, project: project) } - let!(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.id, ref: project.default_branch) } - let!(:build) { create(:ci_build, pipeline: pipeline) } + let(:reporter) { create(:project_member, :reporter, project: project).user } + let(:guest) { create(:project_member, :guest, project: project).user } + + before do + project.add_developer(user) + end describe 'GET /projects/:id/jobs' do let(:query) { Hash.new } @@ -213,7 +223,7 @@ describe API::Jobs, api: true do end describe 'GET /projects/:id/artifacts/:ref_name/download?job=name' do - let(:api_user) { reporter.user } + let(:api_user) { reporter } let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) } before do @@ -237,7 +247,7 @@ describe API::Jobs, api: true do end context 'when logging as guest' do - let(:api_user) { guest.user } + let(:api_user) { guest } before do get_for_ref @@ -320,7 +330,7 @@ describe API::Jobs, api: true do context 'authorized user' do it 'returns specific job trace' do expect(response).to have_http_status(200) - expect(response.body).to eq(build.trace) + expect(response.body).to eq(build.trace.raw) end end @@ -347,7 +357,7 @@ describe API::Jobs, api: true do end context 'user without :update_build permission' do - let(:api_user) { reporter.user } + let(:api_user) { reporter } it 'does not cancel job' do expect(response).to have_http_status(403) @@ -381,7 +391,7 @@ describe API::Jobs, api: true do end context 'user without :update_build permission' do - let(:api_user) { reporter.user } + let(:api_user) { reporter } it 'does not retry job' do expect(response).to have_http_status(403) @@ -408,7 +418,7 @@ describe API::Jobs, api: true do it 'erases job content' do expect(response).to have_http_status(201) - expect(build.trace).to be_empty + expect(build).not_to have_trace expect(build.artifacts_file.exists?).to be_falsy expect(build.artifacts_metadata.exists?).to be_falsy end @@ -457,16 +467,39 @@ describe API::Jobs, api: true do describe 'POST /projects/:id/jobs/:job_id/play' do before do - post api("/projects/#{project.id}/jobs/#{build.id}/play", user) + post api("/projects/#{project.id}/jobs/#{build.id}/play", api_user) end context 'on an playable job' do let(:build) { create(:ci_build, :manual, project: project, pipeline: pipeline) } - it 'plays the job' do - expect(response).to have_http_status(200) - expect(json_response['user']['id']).to eq(user.id) - expect(json_response['id']).to eq(build.id) + context 'when user is authorized to trigger a manual action' do + it 'plays the job' do + expect(response).to have_http_status(200) + expect(json_response['user']['id']).to eq(user.id) + expect(json_response['id']).to eq(build.id) + expect(build.reload).to be_pending + end + end + + context 'when user is not authorized to trigger a manual action' do + context 'when user does not have access to the project' do + let(:api_user) { create(:user) } + + it 'does not trigger a manual action' do + expect(build.reload).to be_manual + expect(response).to have_http_status(404) + end + end + + context 'when user is not allowed to trigger the manual action' do + let(:api_user) { reporter } + + it 'does not trigger a manual action' do + expect(build.reload).to be_manual + expect(response).to have_http_status(403) + end + end end end diff --git a/spec/requests/api/keys_spec.rb b/spec/requests/api/keys_spec.rb index 4c80987d680..ab957c72984 100644 --- a/spec/requests/api/keys_spec.rb +++ b/spec/requests/api/keys_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::Keys, api: true do - include ApiHelpers - +describe API::Keys do let(:user) { create(:user) } let(:admin) { create(:admin) } let(:key) { create(:key, user: user) } @@ -34,6 +32,12 @@ describe API::Keys, api: true do expect(json_response['user']['id']).to eq(user.id) expect(json_response['user']['username']).to eq(user.username) end + + it "does not include the user's `is_admin` flag" do + get api("/keys/#{key.id}", admin) + + expect(json_response['user']['is_admin']).to be_nil + end end end end diff --git a/spec/requests/api/labels_spec.rb b/spec/requests/api/labels_spec.rb index a1adaba7b98..0c6b55c1630 100644 --- a/spec/requests/api/labels_spec.rb +++ b/spec/requests/api/labels_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::Labels, api: true do - include ApiHelpers - +describe API::Labels do let(:user) { create(:user) } let(:project) { create(:empty_project, creator_id: user.id, namespace: user.namespace) } let!(:label1) { create(:label, title: 'label1', project: project) } diff --git a/spec/requests/api/lint_spec.rb b/spec/requests/api/lint_spec.rb index 391fc13a380..df7c91b5bc1 100644 --- a/spec/requests/api/lint_spec.rb +++ b/spec/requests/api/lint_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::Lint, api: true do - include ApiHelpers - +describe API::Lint do describe 'POST /ci/lint' do context 'with valid .gitlab-ci.yaml content' do let(:yaml_content) do diff --git a/spec/requests/api/members_spec.rb b/spec/requests/api/members_spec.rb index 2d37d026a39..e095053fa03 100644 --- a/spec/requests/api/members_spec.rb +++ b/spec/requests/api/members_spec.rb @@ -1,9 +1,7 @@ require 'spec_helper' -describe API::Members, api: true do - include ApiHelpers - - let(:master) { create(:user) } +describe API::Members do + let(:master) { create(:user, username: 'master_user') } let(:developer) { create(:user) } let(:access_requester) { create(:user) } let(:stranger) { create(:user) } diff --git a/spec/requests/api/merge_request_diffs_spec.rb b/spec/requests/api/merge_request_diffs_spec.rb index 79f3151ba52..d1b22179888 100644 --- a/spec/requests/api/merge_request_diffs_spec.rb +++ b/spec/requests/api/merge_request_diffs_spec.rb @@ -1,8 +1,6 @@ require "spec_helper" -describe API::MergeRequestDiffs, 'MergeRequestDiffs', api: true do - include ApiHelpers - +describe API::MergeRequestDiffs, 'MergeRequestDiffs' do let!(:user) { create(:user) } let!(:merge_request) { create(:merge_request, importing: true) } let!(:project) { merge_request.target_project } diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 61d965e8974..16e5efb2f5b 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -1,16 +1,22 @@ require "spec_helper" -describe API::MergeRequests, api: true do - include ApiHelpers +describe API::MergeRequests do let(:base_time) { Time.now } let(:user) { create(:user) } let(:admin) { create(:user, :admin) } let(:non_member) { create(:user) } - let!(:project) { create(:project, :public, :repository, creator: user, namespace: user.namespace) } - let!(:merge_request) { create(:merge_request, :simple, author: user, assignee: user, source_project: project, title: "Test", created_at: base_time) } - let!(:merge_request_closed) { create(:merge_request, state: "closed", author: user, assignee: user, source_project: project, title: "Closed test", created_at: base_time + 1.second) } - let!(:merge_request_merged) { create(:merge_request, state: "merged", author: user, assignee: user, source_project: project, title: "Merged test", created_at: base_time + 2.seconds, merge_commit_sha: '9999999999999999999999999999999999999999') } + let!(:project) { create(:project, :public, :repository, creator: user, namespace: user.namespace, only_allow_merge_if_pipeline_succeeds: false) } let(:milestone) { create(:milestone, title: '1.0.0', project: project) } + let(:milestone1) { create(:milestone, title: '0.9', project: project) } + let!(:merge_request) { create(:merge_request, :simple, milestone: milestone1, author: user, assignee: user, source_project: project, target_project: project, title: "Test", created_at: base_time) } + let!(:merge_request_closed) { create(:merge_request, state: "closed", milestone: milestone1, author: user, assignee: user, source_project: project, target_project: project, title: "Closed test", created_at: base_time + 1.second) } + let!(:merge_request_merged) { create(:merge_request, state: "merged", author: user, assignee: user, source_project: project, target_project: project, title: "Merged test", created_at: base_time + 2.seconds, merge_commit_sha: '9999999999999999999999999999999999999999') } + let!(:note) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "a comment on a MR") } + let!(:note2) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "another comment on a MR") } + let!(:label) do + create(:label, title: 'label', color: '#FFAABB', project: project) + end + let!(:label_link) { create(:label_link, label: label, target: merge_request) } before do project.team << [user, :reporter] @@ -20,6 +26,7 @@ describe API::MergeRequests, api: true do context "when unauthenticated" do it "returns authentication error" do get api("/projects/#{project.id}/merge_requests") + expect(response).to have_http_status(401) end end @@ -100,6 +107,63 @@ describe API::MergeRequests, api: true do expect(response).to match_response_schema('public_api/v4/merge_requests') end + it 'returns an empty array if no issue matches milestone' do + get api("/projects/#{project.id}/merge_requests", user), milestone: '1.0.0' + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(0) + end + + it 'returns an empty array if milestone does not exist' do + get api("/projects/#{project.id}/merge_requests", user), milestone: 'foo' + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(0) + end + + it 'returns an array of merge requests in given milestone' do + get api("/projects/#{project.id}/merge_requests", user), milestone: '0.9' + + expect(json_response.first['title']).to eq merge_request_closed.title + expect(json_response.first['id']).to eq merge_request_closed.id + end + + it 'returns an array of merge requests matching state in milestone' do + get api("/projects/#{project.id}/merge_requests", user), milestone: '0.9', state: 'closed' + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(1) + expect(json_response.first['id']).to eq(merge_request_closed.id) + end + + it 'returns an array of labeled merge requests' do + get api("/projects/#{project.id}/merge_requests?labels=#{label.title}", user) + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(1) + expect(json_response.first['labels']).to eq([label.title]) + end + + it 'returns an array of labeled merge requests where all labels match' do + get api("/projects/#{project.id}/merge_requests?labels=#{label.title},foo,bar", user) + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(0) + end + + it 'returns an empty array if no merge request matches labels' do + get api("/projects/#{project.id}/merge_requests?labels=foo,bar", user) + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(0) + end + context "with ordering" do before do @mr_later = mr_with_later_created_and_updated_at_time @@ -167,7 +231,7 @@ describe API::MergeRequests, api: true do expect(json_response['created_at']).to be_present expect(json_response['updated_at']).to be_present expect(json_response['labels']).to eq(merge_request.label_names) - expect(json_response['milestone']).to be_nil + expect(json_response['milestone']).to be_a Hash expect(json_response['assignee']).to be_a Hash expect(json_response['author']).to be_a Hash expect(json_response['target_branch']).to eq(merge_request.target_branch) @@ -370,6 +434,19 @@ describe API::MergeRequests, api: true do expect(json_response['title']).to eq('Test merge_request') end + it 'returns 422 when target project has disabled merge requests' do + project.project_feature.update(merge_requests_access_level: 0) + + post api("/projects/#{fork_project.id}/merge_requests", user2), + title: 'Test', + target_branch: 'master', + source_branch: 'markdown', + author: user2, + target_project_id: project.id + + expect(response).to have_http_status(422) + end + it "returns 400 when source_branch is missing" do post api("/projects/#{fork_project.id}/merge_requests", user2), title: 'Test merge_request', target_branch: "master", author: user2, target_project_id: project.id @@ -527,6 +604,18 @@ describe API::MergeRequests, api: true do expect(json_response['merge_when_pipeline_succeeds']).to eq(true) end + it "enables merge when pipeline succeeds if the pipeline is active and only_allow_merge_if_pipeline_succeeds is true" do + allow_any_instance_of(MergeRequest).to receive(:head_pipeline).and_return(pipeline) + allow(pipeline).to receive(:active?).and_return(true) + project.update_attribute(:only_allow_merge_if_pipeline_succeeds, true) + + put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user), merge_when_pipeline_succeeds: true + + expect(response).to have_http_status(200) + expect(json_response['title']).to eq('Test') + expect(json_response['merge_when_pipeline_succeeds']).to eq(true) + end + it "returns 404 for an invalid merge request IID" do put api("/projects/#{project.id}/merge_requests/12345/merge", user) diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb index 7fb728fed6f..dd74351a2b1 100644 --- a/spec/requests/api/milestones_spec.rb +++ b/spec/requests/api/milestones_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' -describe API::Milestones, api: true do - include ApiHelpers +describe API::Milestones do let(:user) { create(:user) } let!(:project) { create(:empty_project, namespace: user.namespace ) } let!(:closed_milestone) { create(:closed_milestone, project: project, title: 'version1', description: 'closed milestone') } @@ -306,6 +305,8 @@ describe API::Milestones, api: true do end it 'returns project merge_requests for a particular milestone' do + # eager-load another_merge_request + another_merge_request get api("/projects/#{project.id}/milestones/#{milestone.id}/merge_requests", user) expect(response).to have_http_status(200) diff --git a/spec/requests/api/namespaces_spec.rb b/spec/requests/api/namespaces_spec.rb index da8fa06d0af..3bf16a3ae27 100644 --- a/spec/requests/api/namespaces_spec.rb +++ b/spec/requests/api/namespaces_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' -describe API::Namespaces, api: true do - include ApiHelpers +describe API::Namespaces do let(:admin) { create(:admin) } let(:user) { create(:user) } let!(:group1) { create(:group) } diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb index d8eb8ce921e..6afcd237c3c 100644 --- a/spec/requests/api/notes_spec.rb +++ b/spec/requests/api/notes_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' -describe API::Notes, api: true do - include ApiHelpers +describe API::Notes do let(:user) { create(:user) } let!(:project) { create(:empty_project, :public, namespace: user.namespace) } let!(:issue) { create(:issue, project: project, author: user) } diff --git a/spec/requests/api/notification_settings_spec.rb b/spec/requests/api/notification_settings_spec.rb index 39d3afcb78f..f619b7e6eaf 100644 --- a/spec/requests/api/notification_settings_spec.rb +++ b/spec/requests/api/notification_settings_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::NotificationSettings, api: true do - include ApiHelpers - +describe API::NotificationSettings do let(:user) { create(:user) } let!(:group) { create(:group) } let!(:project) { create(:empty_project, :public, creator_id: user.id, namespace: group) } diff --git a/spec/requests/api/oauth_tokens_spec.rb b/spec/requests/api/oauth_tokens_spec.rb index 367225df717..0d56e1f732e 100644 --- a/spec/requests/api/oauth_tokens_spec.rb +++ b/spec/requests/api/oauth_tokens_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::API, api: true do - include ApiHelpers - +describe 'OAuth tokens' do context 'Resource Owner Password Credentials' do def request_oauth_token(user) post '/oauth/token', username: user.username, password: user.password, grant_type: 'password' diff --git a/spec/requests/api/pipelines_spec.rb b/spec/requests/api/pipelines_spec.rb index 51af999b455..f9e5316b3de 100644 --- a/spec/requests/api/pipelines_spec.rb +++ b/spec/requests/api/pipelines_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::Pipelines, api: true do - include ApiHelpers - +describe API::Pipelines do let(:user) { create(:user) } let(:non_member) { create(:user) } let(:project) { create(:project, :repository, creator: user) } @@ -26,6 +24,245 @@ describe API::Pipelines, api: true do expect(json_response.first['id']).to eq pipeline.id expect(json_response.first.keys).to contain_exactly(*%w[id sha ref status]) end + + context 'when parameter is passed' do + %w[running pending].each do |target| + context "when scope is #{target}" do + before do + create(:ci_pipeline, project: project, status: target) + end + + it 'returns matched pipelines' do + get api("/projects/#{project.id}/pipelines", user), scope: target + + expect(response).to have_http_status(:ok) + expect(response).to include_pagination_headers + expect(json_response).not_to be_empty + json_response.each { |r| expect(r['status']).to eq(target) } + end + end + end + + context 'when scope is finished' do + before do + create(:ci_pipeline, project: project, status: 'success') + create(:ci_pipeline, project: project, status: 'failed') + create(:ci_pipeline, project: project, status: 'canceled') + end + + it 'returns matched pipelines' do + get api("/projects/#{project.id}/pipelines", user), scope: 'finished' + + expect(response).to have_http_status(:ok) + expect(response).to include_pagination_headers + expect(json_response).not_to be_empty + json_response.each { |r| expect(r['status']).to be_in(%w[success failed canceled]) } + end + end + + context 'when scope is branches or tags' do + let!(:pipeline_branch) { create(:ci_pipeline, project: project) } + let!(:pipeline_tag) { create(:ci_pipeline, project: project, ref: 'v1.0.0', tag: true) } + + context 'when scope is branches' do + it 'returns matched pipelines' do + get api("/projects/#{project.id}/pipelines", user), scope: 'branches' + + expect(response).to have_http_status(:ok) + expect(response).to include_pagination_headers + expect(json_response).not_to be_empty + expect(json_response.last['id']).to eq(pipeline_branch.id) + end + end + + context 'when scope is tags' do + it 'returns matched pipelines' do + get api("/projects/#{project.id}/pipelines", user), scope: 'tags' + + expect(response).to have_http_status(:ok) + expect(response).to include_pagination_headers + expect(json_response).not_to be_empty + expect(json_response.last['id']).to eq(pipeline_tag.id) + end + end + end + + context 'when scope is invalid' do + it 'returns bad_request' do + get api("/projects/#{project.id}/pipelines", user), scope: 'invalid-scope' + + expect(response).to have_http_status(:bad_request) + end + end + + HasStatus::AVAILABLE_STATUSES.each do |target| + context "when status is #{target}" do + before do + create(:ci_pipeline, project: project, status: target) + exception_status = HasStatus::AVAILABLE_STATUSES - [target] + create(:ci_pipeline, project: project, status: exception_status.sample) + end + + it 'returns matched pipelines' do + get api("/projects/#{project.id}/pipelines", user), status: target + + expect(response).to have_http_status(:ok) + expect(response).to include_pagination_headers + expect(json_response).not_to be_empty + json_response.each { |r| expect(r['status']).to eq(target) } + end + end + end + + context 'when status is invalid' do + it 'returns bad_request' do + get api("/projects/#{project.id}/pipelines", user), status: 'invalid-status' + + expect(response).to have_http_status(:bad_request) + end + end + + context 'when ref is specified' do + before do + create(:ci_pipeline, project: project) + end + + context 'when ref exists' do + it 'returns matched pipelines' do + get api("/projects/#{project.id}/pipelines", user), ref: 'master' + + expect(response).to have_http_status(:ok) + expect(response).to include_pagination_headers + expect(json_response).not_to be_empty + json_response.each { |r| expect(r['ref']).to eq('master') } + end + end + + context 'when ref does not exist' do + it 'returns empty' do + get api("/projects/#{project.id}/pipelines", user), ref: 'invalid-ref' + + expect(response).to have_http_status(:ok) + expect(response).to include_pagination_headers + expect(json_response).to be_empty + end + end + end + + context 'when name is specified' do + let!(:pipeline) { create(:ci_pipeline, project: project, user: user) } + + context 'when name exists' do + it 'returns matched pipelines' do + get api("/projects/#{project.id}/pipelines", user), name: user.name + + expect(response).to have_http_status(:ok) + expect(response).to include_pagination_headers + expect(json_response.first['id']).to eq(pipeline.id) + end + end + + context 'when name does not exist' do + it 'returns empty' do + get api("/projects/#{project.id}/pipelines", user), name: 'invalid-name' + + expect(response).to have_http_status(:ok) + expect(response).to include_pagination_headers + expect(json_response).to be_empty + end + end + end + + context 'when username is specified' do + let!(:pipeline) { create(:ci_pipeline, project: project, user: user) } + + context 'when username exists' do + it 'returns matched pipelines' do + get api("/projects/#{project.id}/pipelines", user), username: user.username + + expect(response).to have_http_status(:ok) + expect(response).to include_pagination_headers + expect(json_response.first['id']).to eq(pipeline.id) + end + end + + context 'when username does not exist' do + it 'returns empty' do + get api("/projects/#{project.id}/pipelines", user), username: 'invalid-username' + + expect(response).to have_http_status(:ok) + expect(response).to include_pagination_headers + expect(json_response).to be_empty + end + end + end + + context 'when yaml_errors is specified' do + let!(:pipeline1) { create(:ci_pipeline, project: project, yaml_errors: 'Syntax error') } + let!(:pipeline2) { create(:ci_pipeline, project: project) } + + context 'when yaml_errors is true' do + it 'returns matched pipelines' do + get api("/projects/#{project.id}/pipelines", user), yaml_errors: true + + expect(response).to have_http_status(:ok) + expect(response).to include_pagination_headers + expect(json_response.first['id']).to eq(pipeline1.id) + end + end + + context 'when yaml_errors is false' do + it 'returns matched pipelines' do + get api("/projects/#{project.id}/pipelines", user), yaml_errors: false + + expect(response).to have_http_status(:ok) + expect(response).to include_pagination_headers + expect(json_response.first['id']).to eq(pipeline2.id) + end + end + + context 'when yaml_errors is invalid' do + it 'returns bad_request' do + get api("/projects/#{project.id}/pipelines", user), yaml_errors: 'invalid-yaml_errors' + + expect(response).to have_http_status(:bad_request) + end + end + end + + context 'when order_by and sort are specified' do + context 'when order_by user_id' do + let!(:pipeline) { create_list(:ci_pipeline, 2, project: project, user: create(:user)) } + + it 'sorts as user_id: :asc' do + get api("/projects/#{project.id}/pipelines", user), order_by: 'user_id', sort: 'asc' + + expect(response).to have_http_status(:ok) + expect(response).to include_pagination_headers + expect(json_response).not_to be_empty + pipeline.sort_by { |p| p.user.id }.tap do |sorted_pipeline| + json_response.each_with_index { |r, i| expect(r['id']).to eq(sorted_pipeline[i].id) } + end + end + + context 'when sort is invalid' do + it 'returns bad_request' do + get api("/projects/#{project.id}/pipelines", user), order_by: 'user_id', sort: 'invalid_sort' + + expect(response).to have_http_status(:bad_request) + end + end + end + + context 'when order_by is invalid' do + it 'returns bad_request' do + get api("/projects/#{project.id}/pipelines", user), order_by: 'lock_version', sort: 'asc' + + expect(response).to have_http_status(:bad_request) + end + end + end + end end context 'unauthorized user' do diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb index b1f8c249092..0f9330b062d 100644 --- a/spec/requests/api/project_hooks_spec.rb +++ b/spec/requests/api/project_hooks_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' -describe API::ProjectHooks, 'ProjectHooks', api: true do - include ApiHelpers +describe API::ProjectHooks, 'ProjectHooks' do let(:user) { create(:user) } let(:user3) { create(:user) } let!(:project) { create(:empty_project, creator_id: user.id, namespace: user.namespace) } @@ -22,8 +21,8 @@ describe API::ProjectHooks, 'ProjectHooks', api: true do context "authorized user" do it "returns project hooks" do get api("/projects/#{project.id}/hooks", user) - expect(response).to have_http_status(200) + expect(response).to have_http_status(200) expect(json_response).to be_an Array expect(response).to include_pagination_headers expect(json_response.count).to eq(1) @@ -43,6 +42,7 @@ describe API::ProjectHooks, 'ProjectHooks', api: true do context "unauthorized user" do it "does not access project hooks" do get api("/projects/#{project.id}/hooks", user3) + expect(response).to have_http_status(403) end end @@ -52,6 +52,7 @@ describe API::ProjectHooks, 'ProjectHooks', api: true do context "authorized user" do it "returns a project hook" do get api("/projects/#{project.id}/hooks/#{hook.id}", user) + expect(response).to have_http_status(200) expect(json_response['url']).to eq(hook.url) expect(json_response['issues_events']).to eq(hook.issues_events) @@ -59,7 +60,7 @@ describe API::ProjectHooks, 'ProjectHooks', api: true do expect(json_response['merge_requests_events']).to eq(hook.merge_requests_events) expect(json_response['tag_push_events']).to eq(hook.tag_push_events) expect(json_response['note_events']).to eq(hook.note_events) - expect(json_response['job_events']).to eq(hook.build_events) + expect(json_response['job_events']).to eq(hook.job_events) expect(json_response['pipeline_events']).to eq(hook.pipeline_events) expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events) expect(json_response['enable_ssl_verification']).to eq(hook.enable_ssl_verification) @@ -67,6 +68,7 @@ describe API::ProjectHooks, 'ProjectHooks', api: true do it "returns a 404 error if hook id is not available" do get api("/projects/#{project.id}/hooks/1234", user) + expect(response).to have_http_status(404) end end @@ -88,7 +90,8 @@ describe API::ProjectHooks, 'ProjectHooks', api: true do it "adds hook to project" do expect do post api("/projects/#{project.id}/hooks", user), - url: "http://example.com", issues_events: true, wiki_page_events: true + url: "http://example.com", issues_events: true, wiki_page_events: true, + job_events: true end.to change {project.hooks.count}.by(1) expect(response).to have_http_status(201) @@ -98,7 +101,7 @@ describe API::ProjectHooks, 'ProjectHooks', api: true do expect(json_response['merge_requests_events']).to eq(false) expect(json_response['tag_push_events']).to eq(false) expect(json_response['note_events']).to eq(false) - expect(json_response['job_events']).to eq(false) + expect(json_response['job_events']).to eq(true) expect(json_response['pipeline_events']).to eq(false) expect(json_response['wiki_page_events']).to eq(true) expect(json_response['enable_ssl_verification']).to eq(true) @@ -136,7 +139,8 @@ describe API::ProjectHooks, 'ProjectHooks', api: true do describe "PUT /projects/:id/hooks/:hook_id" do it "updates an existing project hook" do put api("/projects/#{project.id}/hooks/#{hook.id}", user), - url: 'http://example.org', push_events: false + url: 'http://example.org', push_events: false, job_events: true + expect(response).to have_http_status(200) expect(json_response['url']).to eq('http://example.org') expect(json_response['issues_events']).to eq(hook.issues_events) @@ -144,7 +148,7 @@ describe API::ProjectHooks, 'ProjectHooks', api: true do expect(json_response['merge_requests_events']).to eq(hook.merge_requests_events) expect(json_response['tag_push_events']).to eq(hook.tag_push_events) expect(json_response['note_events']).to eq(hook.note_events) - expect(json_response['job_events']).to eq(hook.build_events) + expect(json_response['job_events']).to eq(hook.job_events) expect(json_response['pipeline_events']).to eq(hook.pipeline_events) expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events) expect(json_response['enable_ssl_verification']).to eq(hook.enable_ssl_verification) diff --git a/spec/requests/api/project_snippets_spec.rb b/spec/requests/api/project_snippets_spec.rb index 9e88c19b0bc..3ab1764f5c3 100644 --- a/spec/requests/api/project_snippets_spec.rb +++ b/spec/requests/api/project_snippets_spec.rb @@ -1,8 +1,6 @@ require 'rails_helper' -describe API::ProjectSnippets, api: true do - include ApiHelpers - +describe API::ProjectSnippets do let(:project) { create(:empty_project, :public) } let(:user) { create(:user) } let(:admin) { create(:admin) } diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index a3de4702ad0..d5c3b5b34ad 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- require 'spec_helper' -describe API::Projects, :api do +describe API::Projects do include Gitlab::CurrentSettings let(:user) { create(:user) } @@ -24,6 +24,7 @@ describe API::Projects, :api do namespace: user.namespace, merge_requests_enabled: false, issues_enabled: false, wiki_enabled: false, + builds_enabled: false, snippets_enabled: false) end let(:project_member3) do @@ -341,8 +342,8 @@ describe API::Projects, :api do it "assigns attributes to project" do project = attributes_for(:project, { path: 'camelCasePath', - description: FFaker::Lorem.sentence, issues_enabled: false, + jobs_enabled: false, merge_requests_enabled: false, wiki_enabled: false, only_allow_merge_if_pipeline_succeeds: false, @@ -352,6 +353,8 @@ describe API::Projects, :api do post api('/projects', user), project + expect(response).to have_http_status(201) + project.each_pair do |k, v| next if %i[has_external_issue_tracker issues_enabled merge_requests_enabled wiki_enabled].include?(k) expect(json_response[k.to_s]).to eq(v) @@ -475,7 +478,6 @@ describe API::Projects, :api do it 'assigns attributes to project' do project = attributes_for(:project, { - description: FFaker::Lorem.sentence, issues_enabled: false, merge_requests_enabled: false, wiki_enabled: false, @@ -659,10 +661,24 @@ describe API::Projects, :api do 'name' => user.namespace.name, 'path' => user.namespace.path, 'kind' => user.namespace.kind, - 'full_path' => user.namespace.full_path, + 'full_path' => user.namespace.full_path }) end + it "does not include statistics by default" do + get api("/projects/#{project.id}", user) + + expect(response).to have_http_status(200) + expect(json_response).not_to include 'statistics' + end + + it "includes statistics if requested" do + get api("/projects/#{project.id}", user), statistics: true + + expect(response).to have_http_status(200) + expect(json_response).to include 'statistics' + end + describe 'permissions' do context 'all projects' do before { project.team << [user, :master] } @@ -1078,10 +1094,21 @@ describe API::Projects, :api do before { project_member3 } before { project_member2 } + it 'returns 400 when nothing sent' do + project_param = {} + + put api("/projects/#{project.id}", user), project_param + + expect(response).to have_http_status(400) + expect(json_response['error']).to match('at least one parameter must be provided') + end + context 'when unauthenticated' do it 'returns authentication error' do project_param = { name: 'bar' } + put api("/projects/#{project.id}"), project_param + expect(response).to have_http_status(401) end end @@ -1089,8 +1116,11 @@ describe API::Projects, :api do context 'when authenticated as project owner' do it 'updates name' do project_param = { name: 'bar' } + put api("/projects/#{project.id}", user), project_param + expect(response).to have_http_status(200) + project_param.each_pair do |k, v| expect(json_response[k.to_s]).to eq(v) end @@ -1098,8 +1128,11 @@ describe API::Projects, :api do it 'updates visibility_level' do project_param = { visibility: 'public' } + put api("/projects/#{project3.id}", user), project_param + expect(response).to have_http_status(200) + project_param.each_pair do |k, v| expect(json_response[k.to_s]).to eq(v) end @@ -1108,17 +1141,23 @@ describe API::Projects, :api do it 'updates visibility_level from public to private' do project3.update_attributes({ visibility_level: Gitlab::VisibilityLevel::PUBLIC }) project_param = { visibility: 'private' } + put api("/projects/#{project3.id}", user), project_param + expect(response).to have_http_status(200) + project_param.each_pair do |k, v| expect(json_response[k.to_s]).to eq(v) end + expect(json_response['visibility']).to eq('private') end it 'does not update name to existing name' do project_param = { name: project3.name } + put api("/projects/#{project.id}", user), project_param + expect(response).to have_http_status(400) expect(json_response['message']['name']).to eq(['has already been taken']) end @@ -1134,8 +1173,23 @@ describe API::Projects, :api do it 'updates path & name to existing path & name in different namespace' do project_param = { path: project4.path, name: project4.name } + + put api("/projects/#{project3.id}", user), project_param + + expect(response).to have_http_status(200) + + project_param.each_pair do |k, v| + expect(json_response[k.to_s]).to eq(v) + end + end + + it 'updates jobs_enabled' do + project_param = { jobs_enabled: true } + put api("/projects/#{project3.id}", user), project_param + expect(response).to have_http_status(200) + project_param.each_pair do |k, v| expect(json_response[k.to_s]).to eq(v) end diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb index 4783d011d54..1a0695615e3 100644 --- a/spec/requests/api/repositories_spec.rb +++ b/spec/requests/api/repositories_spec.rb @@ -1,8 +1,7 @@ require 'spec_helper' require 'mime/types' -describe API::Repositories, api: true do - include ApiHelpers +describe API::Repositories do include RepoHelpers include WorkhorseHelpers diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb index 044b989e5ba..be83514ed9c 100644 --- a/spec/requests/api/runner_spec.rb +++ b/spec/requests/api/runner_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' describe API::Runner do - include ApiHelpers include StubGitlabCalls let(:registration_token) { 'abcdefg123456' } @@ -461,6 +460,29 @@ describe API::Runner do end end + context 'when dependencies is an empty array' do + let!(:job) { create(:ci_build_tag, pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0) } + let!(:job2) { create(:ci_build_tag, pipeline: pipeline, name: 'rubocop', stage: 'test', stage_idx: 0) } + let!(:empty_dependencies_job) do + create(:ci_build, pipeline: pipeline, token: 'test-job-token', name: 'empty_dependencies_job', + stage: 'deploy', stage_idx: 1, + options: { dependencies: [] }) + end + + before do + job.success + job2.success + end + + it 'returns an empty array' do + request_job + + expect(response).to have_http_status(201) + expect(json_response['id']).to eq(empty_dependencies_job.id) + expect(json_response['dependencies'].count).to eq(0) + end + end + context 'when job has no tags' do before { job.update(tags: []) } @@ -569,7 +591,7 @@ describe API::Runner do update_job(trace: 'BUILD TRACE UPDATED') expect(response).to have_http_status(200) - expect(job.reload.trace).to eq 'BUILD TRACE UPDATED' + expect(job.reload.trace.raw).to eq 'BUILD TRACE UPDATED' end end @@ -577,7 +599,7 @@ describe API::Runner do it 'does not override trace information' do update_job - expect(job.reload.trace).to eq 'BUILD TRACE' + expect(job.reload.trace.raw).to eq 'BUILD TRACE' end end @@ -608,7 +630,7 @@ describe API::Runner do context 'when request is valid' do it 'gets correct response' do expect(response.status).to eq 202 - expect(job.reload.trace).to eq 'BUILD TRACE appended' + expect(job.reload.trace.raw).to eq 'BUILD TRACE appended' expect(response.header).to have_key 'Range' expect(response.header).to have_key 'Job-Status' end @@ -619,7 +641,7 @@ describe API::Runner do it "changes the job's trace" do patch_the_trace - expect(job.reload.trace).to eq 'BUILD TRACE appended appended' + expect(job.reload.trace.raw).to eq 'BUILD TRACE appended appended' end context 'when Runner makes a force-patch' do @@ -628,7 +650,7 @@ describe API::Runner do it "doesn't change the build.trace" do force_patch_the_trace - expect(job.reload.trace).to eq 'BUILD TRACE appended' + expect(job.reload.trace.raw).to eq 'BUILD TRACE appended' end end end @@ -641,7 +663,7 @@ describe API::Runner do it 'changes the job.trace' do patch_the_trace - expect(job.reload.trace).to eq 'BUILD TRACE appended appended' + expect(job.reload.trace.raw).to eq 'BUILD TRACE appended appended' end context 'when Runner makes a force-patch' do @@ -650,7 +672,7 @@ describe API::Runner do it "doesn't change the job.trace" do force_patch_the_trace - expect(job.reload.trace).to eq 'BUILD TRACE appended' + expect(job.reload.trace.raw).to eq 'BUILD TRACE appended' end end end @@ -675,7 +697,7 @@ describe API::Runner do it 'gets correct response' do expect(response.status).to eq 202 - expect(job.reload.trace).to eq 'BUILD TRACE appended' + expect(job.reload.trace.raw).to eq 'BUILD TRACE appended' expect(response.header).to have_key 'Range' expect(response.header).to have_key 'Job-Status' end @@ -715,9 +737,11 @@ describe API::Runner do def patch_the_trace(content = ' appended', request_headers = nil) unless request_headers - offset = job.trace_length - limit = offset + content.length - 1 - request_headers = headers.merge({ 'Content-Range' => "#{offset}-#{limit}" }) + job.trace.read do |stream| + offset = stream.size + limit = offset + content.length - 1 + request_headers = headers.merge({ 'Content-Range' => "#{offset}-#{limit}" }) + end end Timecop.travel(job.updated_at + update_interval) do diff --git a/spec/requests/api/runners_spec.rb b/spec/requests/api/runners_spec.rb index 8a82543a830..645a5389850 100644 --- a/spec/requests/api/runners_spec.rb +++ b/spec/requests/api/runners_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::Runners, api: true do - include ApiHelpers - +describe API::Runners do let(:admin) { create(:user, :admin) } let(:user) { create(:user) } let(:user2) { create(:user) } diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb index fd334934ca5..95df3429314 100644 --- a/spec/requests/api/services_spec.rb +++ b/spec/requests/api/services_spec.rb @@ -1,8 +1,6 @@ require "spec_helper" -describe API::Services, api: true do - include ApiHelpers - +describe API::Services do let(:user) { create(:user) } let(:admin) { create(:admin) } let(:user2) { create(:user) } diff --git a/spec/requests/api/session_spec.rb b/spec/requests/api/session_spec.rb index 28fab2011a5..5e77519c867 100644 --- a/spec/requests/api/session_spec.rb +++ b/spec/requests/api/session_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::Session, api: true do - include ApiHelpers - +describe API::Session do let(:user) { create(:user) } describe "POST /session" do @@ -13,7 +11,7 @@ describe API::Session, api: true do expect(json_response['email']).to eq(user.email) expect(json_response['private_token']).to eq(user.private_token) - expect(json_response['is_admin']).to eq(user.is_admin?) + expect(json_response['is_admin']).to eq(user.admin?) expect(json_response['can_create_project']).to eq(user.can_create_project?) expect(json_response['can_create_group']).to eq(user.can_create_group?) end @@ -37,7 +35,7 @@ describe API::Session, api: true do expect(json_response['email']).to eq user.email expect(json_response['private_token']).to eq user.private_token - expect(json_response['is_admin']).to eq user.is_admin? + expect(json_response['is_admin']).to eq user.admin? expect(json_response['can_create_project']).to eq user.can_create_project? expect(json_response['can_create_group']).to eq user.can_create_group? end @@ -50,7 +48,7 @@ describe API::Session, api: true do expect(json_response['email']).to eq user.email expect(json_response['private_token']).to eq user.private_token - expect(json_response['is_admin']).to eq user.is_admin? + expect(json_response['is_admin']).to eq user.admin? expect(json_response['can_create_project']).to eq user.can_create_project? expect(json_response['can_create_group']).to eq user.can_create_group? end diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb index 11b4b718e2c..2398ae6219c 100644 --- a/spec/requests/api/settings_spec.rb +++ b/spec/requests/api/settings_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::Settings, 'Settings', api: true do - include ApiHelpers - +describe API::Settings, 'Settings' do let(:user) { create(:user) } let(:admin) { create(:admin) } diff --git a/spec/requests/api/sidekiq_metrics_spec.rb b/spec/requests/api/sidekiq_metrics_spec.rb index 28067f8ca88..83042d0cb12 100644 --- a/spec/requests/api/sidekiq_metrics_spec.rb +++ b/spec/requests/api/sidekiq_metrics_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::SidekiqMetrics, api: true do - include ApiHelpers - +describe API::SidekiqMetrics do let(:admin) { create(:user, :admin) } describe 'GET sidekiq/*' do diff --git a/spec/requests/api/snippets_spec.rb b/spec/requests/api/snippets_spec.rb index 5d75b47b3cd..e429cddcf6a 100644 --- a/spec/requests/api/snippets_spec.rb +++ b/spec/requests/api/snippets_spec.rb @@ -1,7 +1,6 @@ require 'rails_helper' -describe API::Snippets, api: true do - include ApiHelpers +describe API::Snippets do let!(:user) { create(:user) } describe 'GET /snippets/' do diff --git a/spec/requests/api/system_hooks_spec.rb b/spec/requests/api/system_hooks_spec.rb index d1e10f12657..2eb191d6049 100644 --- a/spec/requests/api/system_hooks_spec.rb +++ b/spec/requests/api/system_hooks_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::SystemHooks, api: true do - include ApiHelpers - +describe API::SystemHooks do let(:user) { create(:user) } let(:admin) { create(:admin) } let!(:hook) { create(:system_hook, url: "http://example.com") } @@ -34,8 +32,9 @@ describe API::SystemHooks, api: true do expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.first['url']).to eq(hook.url) - expect(json_response.first['push_events']).to be true + expect(json_response.first['push_events']).to be false expect(json_response.first['tag_push_events']).to be false + expect(json_response.first['repository_update_events']).to be true end end end diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb index b132d033a61..ef7d0c3ee41 100644 --- a/spec/requests/api/tags_spec.rb +++ b/spec/requests/api/tags_spec.rb @@ -1,8 +1,7 @@ require 'spec_helper' require 'mime/types' -describe API::Tags, api: true do - include ApiHelpers +describe API::Tags do include RepoHelpers let(:user) { create(:user) } diff --git a/spec/requests/api/templates_spec.rb b/spec/requests/api/templates_spec.rb index 2c83e119065..cb55985e3f5 100644 --- a/spec/requests/api/templates_spec.rb +++ b/spec/requests/api/templates_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::Templates, api: true do - include ApiHelpers - +describe API::Templates do context 'the Template Entity' do before { get api('/templates/gitignores/Ruby') } diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb index b789284fa8d..92533f4dfea 100644 --- a/spec/requests/api/todos_spec.rb +++ b/spec/requests/api/todos_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::Todos, api: true do - include ApiHelpers - +describe API::Todos do let(:project_1) { create(:empty_project, :test_repo) } let(:project_2) { create(:empty_project) } let(:author_1) { create(:user) } diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb index d93a734f5b6..16ddade27d9 100644 --- a/spec/requests/api/triggers_spec.rb +++ b/spec/requests/api/triggers_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' describe API::Triggers do - include ApiHelpers - let(:user) { create(:user) } let(:user2) { create(:user) } let!(:trigger_token) { 'secure_token' } diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 04e7837fd7a..4919ad19833 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -1,12 +1,10 @@ require 'spec_helper' -describe API::Users, api: true do - include ApiHelpers - +describe API::Users do let(:user) { create(:user) } let(:admin) { create(:admin) } - let(:key) { create(:key, user: user) } - let(:email) { create(:email, user: user) } + let(:key) { create(:key, user: user) } + let(:email) { create(:email, user: user) } let(:omniauth_user) { create(:omniauth_user) } let(:ldap_user) { create(:omniauth_user, provider: 'ldapmain') } let(:ldap_blocked_user) { create(:omniauth_user, provider: 'ldapmain', state: 'ldap_blocked') } @@ -72,6 +70,12 @@ describe API::Users, api: true do expect(json_response).to be_an Array expect(json_response.first['username']).to eq(omniauth_user.username) end + + it "returns a 403 when non-admin user searches by external UID" do + get api("/users?extern_uid=#{omniauth_user.identities.first.extern_uid}&provider=#{omniauth_user.identities.first.provider}", user) + + expect(response).to have_http_status(403) + end end context "when admin" do @@ -100,6 +104,27 @@ describe API::Users, api: true do expect(json_response).to be_an Array expect(json_response).to all(include('external' => true)) end + + it "returns one user by external UID" do + get api("/users?extern_uid=#{omniauth_user.identities.first.extern_uid}&provider=#{omniauth_user.identities.first.provider}", admin) + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.size).to eq(1) + expect(json_response.first['username']).to eq(omniauth_user.username) + end + + it "returns 400 error if provider with no extern_uid" do + get api("/users?extern_uid=#{omniauth_user.identities.first.extern_uid}", admin) + + expect(response).to have_http_status(400) + end + + it "returns 400 error if provider with no extern_uid" do + get api("/users?provider=#{omniauth_user.identities.first.provider}", admin) + + expect(response).to have_http_status(400) + end end end @@ -110,6 +135,12 @@ describe API::Users, api: true do expect(json_response['username']).to eq(user.username) end + it "does not return the user's `is_admin` flag" do + get api("/users/#{user.id}", user) + + expect(json_response['is_admin']).to be_nil + end + it "returns a 401 if unauthenticated" do get api("/users/9998") expect(response).to have_http_status(401) @@ -129,7 +160,7 @@ describe API::Users, api: true do end describe "POST /users" do - before{ admin } + before { admin } it "creates user" do expect do @@ -214,9 +245,9 @@ describe API::Users, api: true do it "does not create user with invalid email" do post api('/users', admin), - email: 'invalid email', - password: 'password', - name: 'test' + email: 'invalid email', + password: 'password', + name: 'test' expect(response).to have_http_status(400) end @@ -242,12 +273,12 @@ describe API::Users, api: true do it 'returns 400 error if user does not validate' do post api('/users', admin), - password: 'pass', - email: 'test@example.com', - username: 'test!', - name: 'test', - bio: 'g' * 256, - projects_limit: -1 + password: 'pass', + email: 'test@example.com', + username: 'test!', + name: 'test', + bio: 'g' * 256, + projects_limit: -1 expect(response).to have_http_status(400) expect(json_response['message']['password']). to eq(['is too short (minimum is 8 characters)']) @@ -267,19 +298,19 @@ describe API::Users, api: true do context 'with existing user' do before do post api('/users', admin), - email: 'test@example.com', - password: 'password', - username: 'test', - name: 'foo' + email: 'test@example.com', + password: 'password', + username: 'test', + name: 'foo' end it 'returns 409 conflict error if user with same email exists' do expect do post api('/users', admin), - name: 'foo', - email: 'test@example.com', - password: 'password', - username: 'foo' + name: 'foo', + email: 'test@example.com', + password: 'password', + username: 'foo' end.to change { User.count }.by(0) expect(response).to have_http_status(409) expect(json_response['message']).to eq('Email has already been taken') @@ -288,10 +319,10 @@ describe API::Users, api: true do it 'returns 409 conflict error if same username exists' do expect do post api('/users', admin), - name: 'foo', - email: 'foo@example.com', - password: 'password', - username: 'test' + name: 'foo', + email: 'foo@example.com', + password: 'password', + username: 'test' end.to change { User.count }.by(0) expect(response).to have_http_status(409) expect(json_response['message']).to eq('Username has already been taken') @@ -372,7 +403,6 @@ describe API::Users, api: true do it "updates admin status" do put api("/users/#{user.id}", admin), { admin: true } expect(response).to have_http_status(200) - expect(json_response['is_admin']).to eq(true) expect(user.reload.admin).to eq(true) end @@ -386,7 +416,6 @@ describe API::Users, api: true do it "does not update admin status" do put api("/users/#{admin_user.id}", admin), { can_create_group: false } expect(response).to have_http_status(200) - expect(json_response['is_admin']).to eq(true) expect(admin_user.reload.admin).to eq(true) expect(admin_user.can_create_group).to eq(false) end @@ -416,12 +445,12 @@ describe API::Users, api: true do it 'returns 400 error if user does not validate' do put api("/users/#{user.id}", admin), - password: 'pass', - email: 'test@example.com', - username: 'test!', - name: 'test', - bio: 'g' * 256, - projects_limit: -1 + password: 'pass', + email: 'test@example.com', + username: 'test!', + name: 'test', + bio: 'g' * 256, + projects_limit: -1 expect(response).to have_http_status(400) expect(json_response['message']['password']). to eq(['is too short (minimum is 8 characters)']) @@ -488,7 +517,7 @@ describe API::Users, api: true do key_attrs = attributes_for :key expect do post api("/users/#{user.id}/keys", admin), key_attrs - end.to change{ user.keys.count }.by(1) + end.to change { user.keys.count }.by(1) end it "returns 400 for invalid ID" do @@ -580,7 +609,7 @@ describe API::Users, api: true do email_attrs = attributes_for :email expect do post api("/users/#{user.id}/emails", admin), email_attrs - end.to change{ user.emails.count }.by(1) + end.to change { user.emails.count }.by(1) end it "returns a 400 for invalid ID" do @@ -676,7 +705,7 @@ describe API::Users, api: true do before { admin } it "deletes user" do - delete api("/users/#{user.id}", admin) + Sidekiq::Testing.inline! { delete api("/users/#{user.id}", admin) } expect(response).to have_http_status(204) expect { User.find(user.id) }.to raise_error ActiveRecord::RecordNotFound @@ -684,23 +713,23 @@ describe API::Users, api: true do end it "does not delete for unauthenticated user" do - delete api("/users/#{user.id}") + Sidekiq::Testing.inline! { delete api("/users/#{user.id}") } expect(response).to have_http_status(401) end it "is not available for non admin users" do - delete api("/users/#{user.id}", user) + Sidekiq::Testing.inline! { delete api("/users/#{user.id}", user) } expect(response).to have_http_status(403) end it "returns 404 for non-existing user" do - delete api("/users/999999", admin) + Sidekiq::Testing.inline! { delete api("/users/999999", admin) } expect(response).to have_http_status(404) expect(json_response['message']).to eq('404 User Not Found') end it "returns a 404 for invalid ID" do - delete api("/users/ASDF", admin) + Sidekiq::Testing.inline! { delete api("/users/ASDF", admin) } expect(response).to have_http_status(404) end @@ -842,7 +871,7 @@ describe API::Users, api: true do key_attrs = attributes_for :key expect do post api("/user/keys", user), key_attrs - end.to change{ user.keys.count }.by(1) + end.to change { user.keys.count }.by(1) expect(response).to have_http_status(201) end @@ -880,7 +909,7 @@ describe API::Users, api: true do delete api("/user/keys/#{key.id}", user) expect(response).to have_http_status(204) - end.to change{user.keys.count}.by(-1) + end.to change { user.keys.count}.by(-1) end it "returns 404 if key ID not found" do @@ -963,7 +992,7 @@ describe API::Users, api: true do email_attrs = attributes_for :email expect do post api("/user/emails", user), email_attrs - end.to change{ user.emails.count }.by(1) + end.to change { user.emails.count }.by(1) expect(response).to have_http_status(201) end @@ -989,7 +1018,7 @@ describe API::Users, api: true do delete api("/user/emails/#{email.id}", user) expect(response).to have_http_status(204) - end.to change{user.emails.count}.by(-1) + end.to change { user.emails.count}.by(-1) end it "returns 404 if email ID not found" do @@ -1158,6 +1187,49 @@ describe API::Users, api: true do end end + context "user activities", :redis do + let!(:old_active_user) { create(:user, last_activity_on: Time.utc(2000, 1, 1)) } + let!(:newly_active_user) { create(:user, last_activity_on: 2.days.ago.midday) } + + context 'last activity as normal user' do + it 'has no permission' do + get api("/user/activities", user) + + expect(response).to have_http_status(403) + end + end + + context 'as admin' do + it 'returns the activities from the last 6 months' do + get api("/user/activities", admin) + + expect(response).to include_pagination_headers + expect(json_response.size).to eq(1) + + activity = json_response.last + + expect(activity['username']).to eq(newly_active_user.username) + expect(activity['last_activity_on']).to eq(2.days.ago.to_date.to_s) + expect(activity['last_activity_at']).to eq(2.days.ago.to_date.to_s) + end + + context 'passing a :from parameter' do + it 'returns the activities from the given date' do + get api("/user/activities?from=2000-1-1", admin) + + expect(response).to include_pagination_headers + expect(json_response.size).to eq(2) + + activity = json_response.first + + expect(activity['username']).to eq(old_active_user.username) + expect(activity['last_activity_on']).to eq(Time.utc(2000, 1, 1).to_date.to_s) + expect(activity['last_activity_at']).to eq(Time.utc(2000, 1, 1).to_date.to_s) + end + end + end + end + describe 'GET /users/:user_id/impersonation_tokens' do let!(:active_personal_access_token) { create(:personal_access_token, user: user) } let!(:revoked_personal_access_token) { create(:personal_access_token, :revoked, user: user) } diff --git a/spec/requests/api/v3/award_emoji_spec.rb b/spec/requests/api/v3/award_emoji_spec.rb index eeb4d128c1b..9234710f488 100644 --- a/spec/requests/api/v3/award_emoji_spec.rb +++ b/spec/requests/api/v3/award_emoji_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::V3::AwardEmoji, api: true do - include ApiHelpers - +describe API::V3::AwardEmoji do let(:user) { create(:user) } let!(:project) { create(:empty_project) } let(:issue) { create(:issue, project: project) } diff --git a/spec/requests/api/v3/boards_spec.rb b/spec/requests/api/v3/boards_spec.rb index eb95934f354..4d786331d1b 100644 --- a/spec/requests/api/v3/boards_spec.rb +++ b/spec/requests/api/v3/boards_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::V3::Boards, api: true do - include ApiHelpers - +describe API::V3::Boards do let(:user) { create(:user) } let(:guest) { create(:user) } let(:non_member) { create(:user) } diff --git a/spec/requests/api/v3/branches_spec.rb b/spec/requests/api/v3/branches_spec.rb index 5dcd4f21f4e..c88f7788697 100644 --- a/spec/requests/api/v3/branches_spec.rb +++ b/spec/requests/api/v3/branches_spec.rb @@ -1,9 +1,7 @@ require 'spec_helper' require 'mime/types' -describe API::V3::Branches, api: true do - include ApiHelpers - +describe API::V3::Branches do let(:user) { create(:user) } let(:user2) { create(:user) } let!(:project) { create(:project, :repository, creator: user) } @@ -49,19 +47,6 @@ describe API::V3::Branches, api: true do delete v3_api("/projects/#{project.id}/repository/branches/foobar", user) expect(response).to have_http_status(404) end - - it "removes protected branch" do - create(:protected_branch, project: project, name: branch_name) - delete v3_api("/projects/#{project.id}/repository/branches/#{branch_name}", user) - expect(response).to have_http_status(405) - expect(json_response['message']).to eq('Protected branch cant be removed') - end - - it "does not remove HEAD branch" do - delete v3_api("/projects/#{project.id}/repository/branches/master", user) - expect(response).to have_http_status(405) - expect(json_response['message']).to eq('Cannot remove HEAD branch') - end end describe "DELETE /projects/:id/repository/merged_branches" do diff --git a/spec/requests/api/v3/broadcast_messages_spec.rb b/spec/requests/api/v3/broadcast_messages_spec.rb index 06556401a29..948cd78c177 100644 --- a/spec/requests/api/v3/broadcast_messages_spec.rb +++ b/spec/requests/api/v3/broadcast_messages_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::V3::BroadcastMessages, api: true do - include ApiHelpers - +describe API::V3::BroadcastMessages do let(:user) { create(:user) } let(:admin) { create(:admin) } diff --git a/spec/requests/api/v3/builds_spec.rb b/spec/requests/api/v3/builds_spec.rb index a50c22a6dd1..dc95599546c 100644 --- a/spec/requests/api/v3/builds_spec.rb +++ b/spec/requests/api/v3/builds_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::V3::Builds, api: true do - include ApiHelpers - +describe API::V3::Builds do let(:user) { create(:user) } let(:api_user) { user } let!(:project) { create(:project, :repository, creator: user, public_builds: false) } @@ -330,7 +328,7 @@ describe API::V3::Builds, api: true do context 'authorized user' do it 'returns specific job trace' do expect(response).to have_http_status(200) - expect(response.body).to eq(build.trace) + expect(response.body).to eq(build.trace.raw) end end @@ -418,7 +416,7 @@ describe API::V3::Builds, api: true do it 'erases job content' do expect(response.status).to eq 201 - expect(build.trace).to be_empty + expect(build).not_to have_trace expect(build.artifacts_file.exists?).to be_falsy expect(build.artifacts_metadata.exists?).to be_falsy end diff --git a/spec/requests/api/v3/commits_spec.rb b/spec/requests/api/v3/commits_spec.rb index adba3a787aa..c2e8c3ae6f7 100644 --- a/spec/requests/api/v3/commits_spec.rb +++ b/spec/requests/api/v3/commits_spec.rb @@ -1,8 +1,7 @@ require 'spec_helper' require 'mime/types' -describe API::V3::Commits, api: true do - include ApiHelpers +describe API::V3::Commits do let(:user) { create(:user) } let(:user2) { create(:user) } let!(:project) { create(:project, :repository, creator: user, namespace: user.namespace) } @@ -485,8 +484,7 @@ describe API::V3::Commits, api: true 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.') + expect(json_response['message']).to include('Sorry, we cannot cherry-pick this commit automatically.') end it 'returns 400 if you are not allowed to push to the target branch' do diff --git a/spec/requests/api/v3/deploy_keys_spec.rb b/spec/requests/api/v3/deploy_keys_spec.rb index f5bdf408c5e..b61b2b618a6 100644 --- a/spec/requests/api/v3/deploy_keys_spec.rb +++ b/spec/requests/api/v3/deploy_keys_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::V3::DeployKeys, api: true do - include ApiHelpers - +describe API::V3::DeployKeys do let(:user) { create(:user) } let(:admin) { create(:admin) } let(:project) { create(:empty_project, creator_id: user.id) } diff --git a/spec/requests/api/v3/deployments_spec.rb b/spec/requests/api/v3/deployments_spec.rb index 3c5ce407b32..0389a264781 100644 --- a/spec/requests/api/v3/deployments_spec.rb +++ b/spec/requests/api/v3/deployments_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::Deployments, api: true do - include ApiHelpers - +describe API::V3::Deployments do let(:user) { create(:user) } let(:non_member) { create(:user) } let(:project) { deployment.environment.project } @@ -26,11 +24,11 @@ describe API::Deployments, api: true do describe 'GET /projects/:id/deployments' do context 'as member of the project' do it_behaves_like 'a paginated resources' do - let(:request) { get api("/projects/#{project.id}/deployments", user) } + let(:request) { get v3_api("/projects/#{project.id}/deployments", user) } end it 'returns projects deployments' do - get api("/projects/#{project.id}/deployments", user) + get v3_api("/projects/#{project.id}/deployments", user) expect(response).to have_http_status(200) expect(json_response).to be_an Array @@ -42,7 +40,7 @@ describe API::Deployments, api: true do context 'as non member' do it 'returns a 404 status code' do - get api("/projects/#{project.id}/deployments", non_member) + get v3_api("/projects/#{project.id}/deployments", non_member) expect(response).to have_http_status(404) end @@ -52,7 +50,7 @@ describe API::Deployments, api: true do describe 'GET /projects/:id/deployments/:deployment_id' do context 'as a member of the project' do it 'returns the projects deployment' do - get api("/projects/#{project.id}/deployments/#{deployment.id}", user) + get v3_api("/projects/#{project.id}/deployments/#{deployment.id}", user) expect(response).to have_http_status(200) expect(json_response['sha']).to match /\A\h{40}\z/ @@ -62,7 +60,7 @@ describe API::Deployments, api: true do context 'as non member' do it 'returns a 404 status code' do - get api("/projects/#{project.id}/deployments/#{deployment.id}", non_member) + get v3_api("/projects/#{project.id}/deployments/#{deployment.id}", non_member) expect(response).to have_http_status(404) end diff --git a/spec/requests/api/v3/environments_spec.rb b/spec/requests/api/v3/environments_spec.rb index 216192c9d34..99f35723974 100644 --- a/spec/requests/api/v3/environments_spec.rb +++ b/spec/requests/api/v3/environments_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::V3::Environments, api: true do - include ApiHelpers - +describe API::V3::Environments do let(:user) { create(:user) } let(:non_member) { create(:user) } let(:project) { create(:empty_project, :private, namespace: user.namespace) } diff --git a/spec/requests/api/v3/files_spec.rb b/spec/requests/api/v3/files_spec.rb index 3b61139a2cd..378ca1720ff 100644 --- a/spec/requests/api/v3/files_spec.rb +++ b/spec/requests/api/v3/files_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::V3::Files, api: true do - include ApiHelpers - +describe API::V3::Files do # 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: @@ -26,8 +24,8 @@ describe API::V3::Files, api: true do ref: 'master' } end - let(:author_email) { FFaker::Internet.email } - let(:author_name) { FFaker::Name.name.chomp("\.") } + let(:author_email) { 'user@example.org' } + let(:author_name) { 'John Doe' } before { project.team << [user, :developer] } @@ -55,7 +53,7 @@ describe API::V3::Files, api: true do let(:params) do { file_path: 'app/models/application.rb', - ref: 'master', + ref: 'master' } end @@ -129,7 +127,7 @@ describe API::V3::Files, api: true do it "returns a 400 if editor fails to create file" do allow_any_instance_of(Repository).to receive(:create_file). - and_return(false) + and_raise(Repository::CommitError, 'Cannot create file') post v3_api("/projects/#{project.id}/repository/files", user), valid_params @@ -229,8 +227,8 @@ describe API::V3::Files, api: true do 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(:delete_file).and_return(false) + it "returns a 400 if fails to delete file" do + allow_any_instance_of(Repository).to receive(:delete_file).and_raise(Repository::CommitError, 'Cannot delete file') delete v3_api("/projects/#{project.id}/repository/files", user), valid_params @@ -265,7 +263,7 @@ describe API::V3::Files, api: true do let(:get_params) do { file_path: file_path, - ref: 'master', + ref: 'master' } end diff --git a/spec/requests/api/v3/groups_spec.rb b/spec/requests/api/v3/groups_spec.rb index a71b7d4b008..bc261b5e07c 100644 --- a/spec/requests/api/v3/groups_spec.rb +++ b/spec/requests/api/v3/groups_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' -describe API::V3::Groups, api: true do - include ApiHelpers +describe API::V3::Groups do include UploadHelpers let(:user1) { create(:user, can_create_group: false) } @@ -70,7 +69,7 @@ describe API::V3::Groups, api: true do storage_size: 702, repository_size: 123, lfs_objects_size: 234, - build_artifacts_size: 345, + build_artifacts_size: 345 }.stringify_keys project1.statistics.update!(attributes) @@ -177,7 +176,7 @@ describe API::V3::Groups, api: true do expect(json_response['path']).to eq(group1.path) expect(json_response['description']).to eq(group1.description) expect(json_response['visibility_level']).to eq(group1.visibility_level) - expect(json_response['avatar_url']).to eq(group1.avatar_url) + expect(json_response['avatar_url']).to eq(group1.avatar_url(only_path: false)) expect(json_response['web_url']).to eq(group1.web_url) expect(json_response['request_access_enabled']).to eq(group1.request_access_enabled) expect(json_response['full_name']).to eq(group1.full_name) diff --git a/spec/requests/api/v3/issues_spec.rb b/spec/requests/api/v3/issues_spec.rb index 383871d5c38..cc81922697a 100644 --- a/spec/requests/api/v3/issues_spec.rb +++ b/spec/requests/api/v3/issues_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' -describe API::V3::Issues, api: true do - include ApiHelpers +describe API::V3::Issues do include EmailHelpers let(:user) { create(:user) } @@ -15,11 +14,11 @@ describe API::V3::Issues, api: true do let!(:closed_issue) do create :closed_issue, author: user, - assignee: user, + assignees: [user], project: project, state: :closed, milestone: milestone, - created_at: generate(:issue_created_at), + created_at: generate(:past_time), updated_at: 3.hours.ago end let!(:confidential_issue) do @@ -27,17 +26,17 @@ describe API::V3::Issues, api: true do :confidential, project: project, author: author, - assignee: assignee, - created_at: generate(:issue_created_at), + assignees: [assignee], + created_at: generate(:past_time), updated_at: 2.hours.ago end let!(:issue) do create :issue, author: user, - assignee: user, + assignees: [user], project: project, milestone: milestone, - created_at: generate(:issue_created_at), + created_at: generate(:past_time), updated_at: 1.hour.ago end let!(:label) do @@ -248,7 +247,7 @@ describe API::V3::Issues, api: true do let!(:group_closed_issue) do create :closed_issue, author: user, - assignee: user, + assignees: [user], project: group_project, state: :closed, milestone: group_milestone, @@ -259,13 +258,13 @@ describe API::V3::Issues, api: true do :confidential, project: group_project, author: author, - assignee: assignee, + assignees: [assignee], updated_at: 2.hours.ago end let!(:group_issue) do create :issue, author: user, - assignee: user, + assignees: [user], project: group_project, milestone: group_milestone, updated_at: 1.hour.ago @@ -738,13 +737,14 @@ describe API::V3::Issues, api: true do describe "POST /projects/:id/issues" do it 'creates a new project issue' do post v3_api("/projects/#{project.id}/issues", user), - title: 'new issue', labels: 'label, label2' + title: 'new issue', labels: 'label, label2', assignee_id: assignee.id 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(%w(label label2)) expect(json_response['confidential']).to be_falsy + expect(json_response['assignee']['name']).to eq(assignee.name) end it 'creates a new confidential project issue' do @@ -824,7 +824,7 @@ describe API::V3::Issues, api: true do end context 'resolving issues in a merge request' do - let(:discussion) { Discussion.for_diff_notes([create(:diff_note_on_merge_request)]).first } + let(:discussion) { create(:diff_note_on_merge_request).to_discussion } let(:merge_request) { discussion.noteable } let(:project) { merge_request.source_project } before do @@ -1141,6 +1141,22 @@ describe API::V3::Issues, api: true do end end + describe 'PUT /projects/:id/issues/:issue_id to update assignee' do + it 'updates an issue with no assignee' do + put v3_api("/projects/#{project.id}/issues/#{issue.id}", user), assignee_id: 0 + + expect(response).to have_http_status(200) + expect(json_response['assignee']).to eq(nil) + end + + it 'updates an issue with assignee' do + put v3_api("/projects/#{project.id}/issues/#{issue.id}", user), assignee_id: user2.id + + expect(response).to have_http_status(200) + expect(json_response['assignee']['name']).to eq(user2.name) + end + end + describe "DELETE /projects/:id/issues/:issue_id" do it "rejects a non member from deleting an issue" do delete v3_api("/projects/#{project.id}/issues/#{issue.id}", non_member) diff --git a/spec/requests/api/v3/labels_spec.rb b/spec/requests/api/v3/labels_spec.rb index dfac357d37c..62faa1cb129 100644 --- a/spec/requests/api/v3/labels_spec.rb +++ b/spec/requests/api/v3/labels_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::V3::Labels, api: true do - include ApiHelpers - +describe API::V3::Labels do let(:user) { create(:user) } let(:project) { create(:empty_project, creator_id: user.id, namespace: user.namespace) } let!(:label1) { create(:label, title: 'label1', project: project) } diff --git a/spec/requests/api/v3/members_spec.rb b/spec/requests/api/v3/members_spec.rb index 13814ed10c3..623f02902b8 100644 --- a/spec/requests/api/v3/members_spec.rb +++ b/spec/requests/api/v3/members_spec.rb @@ -1,9 +1,7 @@ require 'spec_helper' -describe API::V3::Members, api: true do - include ApiHelpers - - let(:master) { create(:user) } +describe API::V3::Members do + let(:master) { create(:user, username: 'master_user') } let(:developer) { create(:user) } let(:access_requester) { create(:user) } let(:stranger) { create(:user) } diff --git a/spec/requests/api/v3/merge_request_diffs_spec.rb b/spec/requests/api/v3/merge_request_diffs_spec.rb index c53800eef30..8020ddab4c8 100644 --- a/spec/requests/api/v3/merge_request_diffs_spec.rb +++ b/spec/requests/api/v3/merge_request_diffs_spec.rb @@ -1,8 +1,6 @@ require "spec_helper" -describe API::V3::MergeRequestDiffs, 'MergeRequestDiffs', api: true do - include ApiHelpers - +describe API::V3::MergeRequestDiffs, 'MergeRequestDiffs' do let!(:user) { create(:user) } let!(:merge_request) { create(:merge_request, importing: true) } let!(:project) { merge_request.target_project } diff --git a/spec/requests/api/v3/merge_requests_spec.rb b/spec/requests/api/v3/merge_requests_spec.rb index d73e9635c9b..f6ff96be566 100644 --- a/spec/requests/api/v3/merge_requests_spec.rb +++ b/spec/requests/api/v3/merge_requests_spec.rb @@ -1,7 +1,6 @@ require "spec_helper" -describe API::MergeRequests, api: true do - include ApiHelpers +describe API::MergeRequests do let(:base_time) { Time.now } let(:user) { create(:user) } let(:admin) { create(:user, :admin) } @@ -339,6 +338,19 @@ describe API::MergeRequests, api: true do expect(json_response['title']).to eq('Test merge_request') end + it "returns 422 when target project has disabled merge requests" do + project.project_feature.update(merge_requests_access_level: 0) + + post v3_api("/projects/#{fork_project.id}/merge_requests", user2), + title: 'Test', + target_branch: "master", + source_branch: 'markdown', + author: user2, + target_project_id: project.id + + expect(response).to have_http_status(422) + end + it "returns 400 when source_branch is missing" do post v3_api("/projects/#{fork_project.id}/merge_requests", user2), title: 'Test merge_request', target_branch: "master", author: user2, target_project_id: project.id diff --git a/spec/requests/api/v3/milestones_spec.rb b/spec/requests/api/v3/milestones_spec.rb index 127c0eec881..f04efc990a7 100644 --- a/spec/requests/api/v3/milestones_spec.rb +++ b/spec/requests/api/v3/milestones_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' -describe API::V3::Milestones, api: true do - include ApiHelpers +describe API::V3::Milestones do let(:user) { create(:user) } let!(:project) { create(:empty_project, namespace: user.namespace ) } let!(:closed_milestone) { create(:closed_milestone, project: project) } diff --git a/spec/requests/api/v3/notes_spec.rb b/spec/requests/api/v3/notes_spec.rb index ddef2d5eb04..2bae4a60931 100644 --- a/spec/requests/api/v3/notes_spec.rb +++ b/spec/requests/api/v3/notes_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::V3::Notes, api: true do - include ApiHelpers - +describe API::V3::Notes do let(:user) { create(:user) } let!(:project) { create(:empty_project, :public, namespace: user.namespace) } let!(:issue) { create(:issue, project: project, author: user) } diff --git a/spec/requests/api/v3/pipelines_spec.rb b/spec/requests/api/v3/pipelines_spec.rb index 3786eb06932..e1d036ff365 100644 --- a/spec/requests/api/v3/pipelines_spec.rb +++ b/spec/requests/api/v3/pipelines_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::V3::Pipelines, api: true do - include ApiHelpers - +describe API::V3::Pipelines do let(:user) { create(:user) } let(:non_member) { create(:user) } let(:project) { create(:project, :repository, creator: user) } diff --git a/spec/requests/api/v3/project_hooks_spec.rb b/spec/requests/api/v3/project_hooks_spec.rb index a981119dc5a..1969d1c7f2b 100644 --- a/spec/requests/api/v3/project_hooks_spec.rb +++ b/spec/requests/api/v3/project_hooks_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' -describe API::ProjectHooks, 'ProjectHooks', api: true do - include ApiHelpers +describe API::ProjectHooks, 'ProjectHooks' do let(:user) { create(:user) } let(:user3) { create(:user) } let!(:project) { create(:project, creator_id: user.id, namespace: user.namespace) } @@ -59,7 +58,7 @@ describe API::ProjectHooks, 'ProjectHooks', api: true do expect(json_response['merge_requests_events']).to eq(hook.merge_requests_events) expect(json_response['tag_push_events']).to eq(hook.tag_push_events) expect(json_response['note_events']).to eq(hook.note_events) - expect(json_response['build_events']).to eq(hook.build_events) + expect(json_response['build_events']).to eq(hook.job_events) expect(json_response['pipeline_events']).to eq(hook.pipeline_events) expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events) expect(json_response['enable_ssl_verification']).to eq(hook.enable_ssl_verification) @@ -144,7 +143,7 @@ describe API::ProjectHooks, 'ProjectHooks', api: true do expect(json_response['merge_requests_events']).to eq(hook.merge_requests_events) expect(json_response['tag_push_events']).to eq(hook.tag_push_events) expect(json_response['note_events']).to eq(hook.note_events) - expect(json_response['build_events']).to eq(hook.build_events) + expect(json_response['build_events']).to eq(hook.job_events) expect(json_response['pipeline_events']).to eq(hook.pipeline_events) expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events) expect(json_response['enable_ssl_verification']).to eq(hook.enable_ssl_verification) diff --git a/spec/requests/api/v3/project_snippets_spec.rb b/spec/requests/api/v3/project_snippets_spec.rb index 957a3bf97ef..365e7365fda 100644 --- a/spec/requests/api/v3/project_snippets_spec.rb +++ b/spec/requests/api/v3/project_snippets_spec.rb @@ -1,8 +1,6 @@ require 'rails_helper' -describe API::ProjectSnippets, api: true do - include ApiHelpers - +describe API::ProjectSnippets do let(:project) { create(:empty_project, :public) } let(:user) { create(:user) } let(:admin) { create(:admin) } diff --git a/spec/requests/api/v3/projects_spec.rb b/spec/requests/api/v3/projects_spec.rb index b1aa793ec00..dc7c3d125b1 100644 --- a/spec/requests/api/v3/projects_spec.rb +++ b/spec/requests/api/v3/projects_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' -describe API::V3::Projects, api: true do - include ApiHelpers +describe API::V3::Projects do include Gitlab::CurrentSettings let(:user) { create(:user) } @@ -228,7 +227,7 @@ describe API::V3::Projects, api: true do storage_size: 702, repository_size: 123, lfs_objects_size: 234, - build_artifacts_size: 345, + build_artifacts_size: 345 } project4.statistics.update!(attributes) @@ -356,7 +355,6 @@ describe API::V3::Projects, api: true do it "assigns attributes to project" do project = attributes_for(:project, { path: 'camelCasePath', - description: FFaker::Lorem.sentence, issues_enabled: false, merge_requests_enabled: false, wiki_enabled: false, @@ -501,7 +499,6 @@ describe API::V3::Projects, api: true do it 'assigns attributes to project' do project = attributes_for(:project, { - description: FFaker::Lorem.sentence, issues_enabled: false, merge_requests_enabled: false, wiki_enabled: false, @@ -709,7 +706,7 @@ describe API::V3::Projects, api: true do 'name' => user.namespace.name, 'path' => user.namespace.path, 'kind' => user.namespace.kind, - 'full_path' => user.namespace.full_path, + 'full_path' => user.namespace.full_path }) end diff --git a/spec/requests/api/v3/repositories_spec.rb b/spec/requests/api/v3/repositories_spec.rb index fef6fb641fa..1a55e2a71cd 100644 --- a/spec/requests/api/v3/repositories_spec.rb +++ b/spec/requests/api/v3/repositories_spec.rb @@ -1,8 +1,7 @@ require 'spec_helper' require 'mime/types' -describe API::V3::Repositories, api: true do - include ApiHelpers +describe API::V3::Repositories do include RepoHelpers include WorkhorseHelpers diff --git a/spec/requests/api/v3/runners_spec.rb b/spec/requests/api/v3/runners_spec.rb index ca335ce9cf0..dbda2cf34c3 100644 --- a/spec/requests/api/v3/runners_spec.rb +++ b/spec/requests/api/v3/runners_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::V3::Runners, api: true do - include ApiHelpers - +describe API::V3::Runners do let(:admin) { create(:user, :admin) } let(:user) { create(:user) } let(:user2) { create(:user) } diff --git a/spec/requests/api/v3/services_spec.rb b/spec/requests/api/v3/services_spec.rb index 3a760a8f25c..3ba62de822a 100644 --- a/spec/requests/api/v3/services_spec.rb +++ b/spec/requests/api/v3/services_spec.rb @@ -1,8 +1,6 @@ require "spec_helper" -describe API::V3::Services, api: true do - include ApiHelpers - +describe API::V3::Services do let(:user) { create(:user) } let(:project) { create(:empty_project, creator_id: user.id, namespace: user.namespace) } diff --git a/spec/requests/api/v3/settings_spec.rb b/spec/requests/api/v3/settings_spec.rb index a9fa5adac17..41d039b7da0 100644 --- a/spec/requests/api/v3/settings_spec.rb +++ b/spec/requests/api/v3/settings_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::V3::Settings, 'Settings', api: true do - include ApiHelpers - +describe API::V3::Settings, 'Settings' do let(:user) { create(:user) } let(:admin) { create(:admin) } diff --git a/spec/requests/api/v3/snippets_spec.rb b/spec/requests/api/v3/snippets_spec.rb index 05653bd0d51..4f02b7b1a54 100644 --- a/spec/requests/api/v3/snippets_spec.rb +++ b/spec/requests/api/v3/snippets_spec.rb @@ -1,7 +1,6 @@ require 'rails_helper' -describe API::V3::Snippets, api: true do - include ApiHelpers +describe API::V3::Snippets do let!(:user) { create(:user) } describe 'GET /snippets/' do diff --git a/spec/requests/api/v3/system_hooks_spec.rb b/spec/requests/api/v3/system_hooks_spec.rb index 91038977c82..ae427541abb 100644 --- a/spec/requests/api/v3/system_hooks_spec.rb +++ b/spec/requests/api/v3/system_hooks_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::V3::SystemHooks, api: true do - include ApiHelpers - +describe API::V3::SystemHooks do let(:user) { create(:user) } let(:admin) { create(:admin) } let!(:hook) { create(:system_hook, url: "http://example.com") } @@ -33,8 +31,9 @@ describe API::V3::SystemHooks, api: true do expect(response).to have_http_status(200) expect(json_response).to be_an Array expect(json_response.first['url']).to eq(hook.url) - expect(json_response.first['push_events']).to be true + expect(json_response.first['push_events']).to be false expect(json_response.first['tag_push_events']).to be false + expect(json_response.first['repository_update_events']).to be true end end end diff --git a/spec/requests/api/v3/tags_spec.rb b/spec/requests/api/v3/tags_spec.rb index 6870cfd2668..1c4b25c47c3 100644 --- a/spec/requests/api/v3/tags_spec.rb +++ b/spec/requests/api/v3/tags_spec.rb @@ -1,8 +1,7 @@ require 'spec_helper' require 'mime/types' -describe API::V3::Tags, api: true do - include ApiHelpers +describe API::V3::Tags do include RepoHelpers let(:user) { create(:user) } diff --git a/spec/requests/api/v3/templates_spec.rb b/spec/requests/api/v3/templates_spec.rb index f1e554b98cc..00446c7f29c 100644 --- a/spec/requests/api/v3/templates_spec.rb +++ b/spec/requests/api/v3/templates_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::V3::Templates, api: true do - include ApiHelpers - +describe API::V3::Templates do shared_examples_for 'the Template Entity' do |path| before { get v3_api(path) } diff --git a/spec/requests/api/v3/todos_spec.rb b/spec/requests/api/v3/todos_spec.rb index 80fa697e949..9c2c4d64257 100644 --- a/spec/requests/api/v3/todos_spec.rb +++ b/spec/requests/api/v3/todos_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::V3::Todos, api: true do - include ApiHelpers - +describe API::V3::Todos do let(:project_1) { create(:empty_project) } let(:project_2) { create(:empty_project) } let(:author_1) { create(:user) } diff --git a/spec/requests/api/v3/triggers_spec.rb b/spec/requests/api/v3/triggers_spec.rb index 9233e9621bf..d3de6bf13bc 100644 --- a/spec/requests/api/v3/triggers_spec.rb +++ b/spec/requests/api/v3/triggers_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' describe API::V3::Triggers do - include ApiHelpers - let(:user) { create(:user) } let(:user2) { create(:user) } let!(:trigger_token) { 'secure_token' } diff --git a/spec/requests/api/v3/users_spec.rb b/spec/requests/api/v3/users_spec.rb index b38cbe74b85..e9c57f7c6c3 100644 --- a/spec/requests/api/v3/users_spec.rb +++ b/spec/requests/api/v3/users_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::V3::Users, api: true do - include ApiHelpers - +describe API::V3::Users do let(:user) { create(:user) } let(:admin) { create(:admin) } let(:key) { create(:key, user: user) } @@ -276,5 +274,11 @@ describe API::V3::Users, api: true do expect(new_user).to be_confirmed end + + it 'does not reveal the `is_admin` flag of the user' do + post v3_api('/users', admin), attributes_for(:user) + + expect(json_response['is_admin']).to be_nil + end end end diff --git a/spec/requests/api/variables_spec.rb b/spec/requests/api/variables_spec.rb index 0c1413119e0..63d6d3001ac 100644 --- a/spec/requests/api/variables_spec.rb +++ b/spec/requests/api/variables_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::Variables, api: true do - include ApiHelpers - +describe API::Variables do let(:user) { create(:user) } let(:user2) { create(:user) } let!(:project) { create(:empty_project, creator_id: user.id) } diff --git a/spec/requests/api/version_spec.rb b/spec/requests/api/version_spec.rb index da1b2fda70e..8870d48bbc9 100644 --- a/spec/requests/api/version_spec.rb +++ b/spec/requests/api/version_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::Version, api: true do - include ApiHelpers - +describe API::Version do describe 'GET /version' do context 'when unauthenticated' do it 'returns authentication error' do diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb index c879f37f50d..286de277ae7 100644 --- a/spec/requests/ci/api/builds_spec.rb +++ b/spec/requests/ci/api/builds_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' describe Ci::API::Builds do - include ApiHelpers - 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 } @@ -187,7 +185,7 @@ describe Ci::API::Builds do { "key" => "CI_PIPELINE_TRIGGERED", "value" => "true", "public" => true }, { "key" => "DB_NAME", "value" => "postgres", "public" => true }, { "key" => "SECRET_KEY", "value" => "secret_value", "public" => false }, - { "key" => "TRIGGER_KEY_1", "value" => "TRIGGER_VALUE_1", "public" => false }, + { "key" => "TRIGGER_KEY_1", "value" => "TRIGGER_VALUE_1", "public" => false } ) end end @@ -285,7 +283,7 @@ describe Ci::API::Builds do end it 'does not override trace information when no trace is given' do - expect(build.reload.trace).to eq 'BUILD TRACE' + expect(build.reload.trace.raw).to eq 'BUILD TRACE' end context 'job has been erased' do @@ -309,9 +307,11 @@ describe Ci::API::Builds do def patch_the_trace(content = ' appended', request_headers = nil) unless request_headers - offset = build.trace_length - limit = offset + content.length - 1 - request_headers = headers.merge({ 'Content-Range' => "#{offset}-#{limit}" }) + build.trace.read do |stream| + offset = stream.size + limit = offset + content.length - 1 + request_headers = headers.merge({ 'Content-Range' => "#{offset}-#{limit}" }) + end end Timecop.travel(build.updated_at + update_interval) do @@ -335,7 +335,7 @@ describe Ci::API::Builds do context 'when request is valid' do it 'gets correct response' do expect(response.status).to eq 202 - expect(build.reload.trace).to eq 'BUILD TRACE appended' + expect(build.reload.trace.raw).to eq 'BUILD TRACE appended' expect(response.header).to have_key 'Range' expect(response.header).to have_key 'Build-Status' end @@ -346,7 +346,7 @@ describe Ci::API::Builds do it 'changes the build trace' do patch_the_trace - expect(build.reload.trace).to eq 'BUILD TRACE appended appended' + expect(build.reload.trace.raw).to eq 'BUILD TRACE appended appended' end context 'when Runner makes a force-patch' do @@ -355,7 +355,7 @@ describe Ci::API::Builds do it "doesn't change the build.trace" do force_patch_the_trace - expect(build.reload.trace).to eq 'BUILD TRACE appended' + expect(build.reload.trace.raw).to eq 'BUILD TRACE appended' end end end @@ -368,7 +368,7 @@ describe Ci::API::Builds do it 'changes the build.trace' do patch_the_trace - expect(build.reload.trace).to eq 'BUILD TRACE appended appended' + expect(build.reload.trace.raw).to eq 'BUILD TRACE appended appended' end context 'when Runner makes a force-patch' do @@ -377,7 +377,7 @@ describe Ci::API::Builds do it "doesn't change the build.trace" do force_patch_the_trace - expect(build.reload.trace).to eq 'BUILD TRACE appended' + expect(build.reload.trace.raw).to eq 'BUILD TRACE appended' end end end @@ -403,7 +403,7 @@ describe Ci::API::Builds do it 'gets correct response' do expect(response.status).to eq 202 - expect(build.reload.trace).to eq 'BUILD TRACE appended' + expect(build.reload.trace.raw).to eq 'BUILD TRACE appended' expect(response.header).to have_key 'Range' expect(response.header).to have_key 'Build-Status' end diff --git a/spec/requests/ci/api/runners_spec.rb b/spec/requests/ci/api/runners_spec.rb index d50cdfdc2d6..0b9733221d8 100644 --- a/spec/requests/ci/api/runners_spec.rb +++ b/spec/requests/ci/api/runners_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' describe Ci::API::Runners do - include ApiHelpers include StubGitlabCalls let(:registration_token) { 'abcdefg123456' } diff --git a/spec/requests/ci/api/triggers_spec.rb b/spec/requests/ci/api/triggers_spec.rb index 5321f8b134f..26b03c0f148 100644 --- a/spec/requests/ci/api/triggers_spec.rb +++ b/spec/requests/ci/api/triggers_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' describe Ci::API::Triggers do - include ApiHelpers - describe 'POST /projects/:project_id/refs/:ref/trigger' do let!(:trigger_token) { 'secure token' } let!(:project) { create(:project, :repository, ci_id: 10) } diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb index 006d6a6af1c..6ca3ef18fe6 100644 --- a/spec/requests/git_http_spec.rb +++ b/spec/requests/git_http_spec.rb @@ -3,6 +3,7 @@ require "spec_helper" describe 'Git HTTP requests', lib: true do include GitHttpHelpers include WorkhorseHelpers + include UserActivitiesHelpers it "gives WWW-Authenticate hints" do clone_get('doesnt/exist.git') @@ -255,6 +256,14 @@ describe 'Git HTTP requests', lib: true do expect(response.content_type.to_s).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE) end end + + it 'updates the user last activity', :redis do + expect(user_activity(user)).to be_nil + + download(path, env) do |response| + expect(user_activity(user)).to be_present + end + end end context "when an oauth token is provided" do @@ -270,10 +279,10 @@ describe 'Git HTTP requests', lib: true do expect(response.content_type.to_s).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE) end - it "uploads get status 401 (no project existence information leak)" do + it "uploads get status 200" do push_get "#{project.path_with_namespace}.git", user: 'oauth2', password: @token.token - expect(response).to have_http_status(401) + expect(response).to have_http_status(200) end end diff --git a/spec/requests/lfs_http_spec.rb b/spec/requests/lfs_http_spec.rb index 5d495bc9e7d..0c9b4121adf 100644 --- a/spec/requests/lfs_http_spec.rb +++ b/spec/requests/lfs_http_spec.rb @@ -425,7 +425,7 @@ describe 'Git LFS API and storage' do 'size' => sample_size, 'error' => { 'code' => 404, - 'message' => "Object does not exist on the server or you don't have permissions to access it", + 'message' => "Object does not exist on the server or you don't have permissions to access it" } } ] @@ -456,7 +456,7 @@ describe 'Git LFS API and storage' do 'size' => 1575078, 'error' => { 'code' => 404, - 'message' => "Object does not exist on the server or you don't have permissions to access it", + 'message' => "Object does not exist on the server or you don't have permissions to access it" } } ] @@ -493,7 +493,7 @@ describe 'Git LFS API and storage' do 'size' => 1575078, 'error' => { 'code' => 404, - 'message' => "Object does not exist on the server or you don't have permissions to access it", + 'message' => "Object does not exist on the server or you don't have permissions to access it" } }, { diff --git a/spec/requests/openid_connect_spec.rb b/spec/requests/openid_connect_spec.rb index 5206634bca5..05176c3beaa 100644 --- a/spec/requests/openid_connect_spec.rb +++ b/spec/requests/openid_connect_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' describe 'OpenID Connect requests' do - include ApiHelpers - let(:user) { create :user } let(:access_grant) { create :oauth_access_grant, application: application, resource_owner_id: user.id } let(:access_token) { create :oauth_access_token, application: application, resource_owner_id: user.id } @@ -63,7 +61,7 @@ describe 'OpenID Connect requests' do email: private_email.email, public_email: public_email.email, website_url: 'https://example.com', - avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png"), + avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png") ) end @@ -81,7 +79,7 @@ describe 'OpenID Connect requests' do 'email_verified' => true, 'website' => 'https://example.com', 'profile' => 'http://localhost/alice', - 'picture' => "http://localhost/uploads/user/avatar/#{user.id}/dk.png", + 'picture' => "http://localhost/uploads/user/avatar/#{user.id}/dk.png" }) end end @@ -100,7 +98,7 @@ describe 'OpenID Connect requests' do expect(@payload['sub']).to eq hashed_subject end - it 'includes the time of the last authentication' do + it 'includes the time of the last authentication', :redis do expect(@payload['auth_time']).to eq user.current_sign_in_at.to_i end diff --git a/spec/requests/projects/artifacts_controller_spec.rb b/spec/requests/projects/artifacts_controller_spec.rb deleted file mode 100644 index d20866c0d44..00000000000 --- a/spec/requests/projects/artifacts_controller_spec.rb +++ /dev/null @@ -1,117 +0,0 @@ -require 'spec_helper' - -describe Projects::ArtifactsController do - let(:user) { create(:user) } - let(:project) { create(:project, :repository) } - - let(:pipeline) do - create(:ci_pipeline, - project: project, - sha: project.commit.sha, - ref: project.default_branch, - status: 'success') - end - - let(:build) { create(:ci_build, :success, :artifacts, pipeline: pipeline) } - - describe 'GET /:project/builds/artifacts/:ref_name/browse?job=name' do - before do - project.team << [user, :developer] - - login_as(user) - end - - def path_from_ref( - ref = pipeline.ref, job = build.name, path = 'browse') - latest_succeeded_namespace_project_artifacts_path( - project.namespace, - project, - [ref, path].join('/'), - job: job) - end - - context 'cannot find the build' do - shared_examples 'not found' do - it { expect(response).to have_http_status(:not_found) } - end - - context 'has no such ref' do - before do - get path_from_ref('TAIL', build.name) - end - - it_behaves_like 'not found' - end - - context 'has no such build' do - before do - get path_from_ref(pipeline.ref, 'NOBUILD') - end - - it_behaves_like 'not found' - end - - context 'has no path' do - before do - get path_from_ref(pipeline.sha, build.name, '') - end - - it_behaves_like 'not found' - end - end - - context 'found the build and redirect' do - shared_examples 'redirect to the build' do - it 'redirects' do - path = browse_namespace_project_build_artifacts_path( - project.namespace, - project, - build) - - expect(response).to redirect_to(path) - end - end - - context 'with regular branch' do - before do - pipeline.update(ref: 'master', - sha: project.commit('master').sha) - - get path_from_ref('master') - end - - it_behaves_like 'redirect to the build' - end - - context 'with branch name containing slash' do - before do - pipeline.update(ref: 'improve/awesome', - sha: project.commit('improve/awesome').sha) - - get path_from_ref('improve/awesome') - end - - it_behaves_like 'redirect to the build' - end - - context 'with branch name and path containing slashes' do - before do - pipeline.update(ref: 'improve/awesome', - sha: project.commit('improve/awesome').sha) - - get path_from_ref('improve/awesome', build.name, 'file/README.md') - end - - it 'redirects' do - path = file_namespace_project_build_artifacts_path( - project.namespace, - project, - build, - 'README.md') - - expect(response).to redirect_to(path) - end - end - end - end -end diff --git a/spec/requests/projects/cycle_analytics_events_spec.rb b/spec/requests/projects/cycle_analytics_events_spec.rb index 0edbffbcd3b..d92daa345b3 100644 --- a/spec/requests/projects/cycle_analytics_events_spec.rb +++ b/spec/requests/projects/cycle_analytics_events_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe 'cycle analytics events' do - include ApiHelpers - +describe 'cycle analytics events', api: true do let(:user) { create(:user) } let(:project) { create(:project, :repository, public_builds: false) } let(:issue) { create(:issue, project: project, created_at: 2.days.ago) } @@ -11,8 +9,6 @@ describe 'cycle analytics events' do before do project.team << [user, :developer] - allow_any_instance_of(Gitlab::ReferenceExtractor).to receive(:issues).and_return([issue]) - 3.times do |count| Timecop.freeze(Time.now + count.days) do create_cycle @@ -123,9 +119,10 @@ describe 'cycle analytics events' do def create_cycle milestone = create(:milestone, project: project) issue.update(milestone: milestone) - mr = create_merge_request_closing_issue(issue) + mr = create_merge_request_closing_issue(issue, commit_message: "References #{issue.to_reference}") pipeline = create(:ci_empty_pipeline, status: 'created', project: project, ref: mr.source_branch, sha: mr.source_branch_sha) + mr.update(head_pipeline_id: pipeline.id) pipeline.run create(:ci_build, pipeline: pipeline, status: :success, author: user) diff --git a/spec/requests/request_profiler_spec.rb b/spec/requests/request_profiler_spec.rb new file mode 100644 index 00000000000..51fbfecec4b --- /dev/null +++ b/spec/requests/request_profiler_spec.rb @@ -0,0 +1,44 @@ +require 'spec_helper' + +describe 'Request Profiler' do + let(:user) { create(:user) } + + shared_examples 'profiling a request' do + before do + allow(Rails).to receive(:cache).and_return(ActiveSupport::Cache::MemoryStore.new) + allow(RubyProf::Profile).to receive(:profile) do |&blk| + blk.call + RubyProf::Profile.new + end + end + + it 'creates a profile of the request' do + project = create(:project, namespace: user.namespace) + time = Time.now + path = "/#{project.path_with_namespace}" + + Timecop.freeze(time) do + get path, nil, 'X-Profile-Token' => Gitlab::RequestProfiler.profile_token + end + + profile_path = "#{Gitlab.config.shared.path}/tmp/requests_profiles/#{path.tr('/', '|')}_#{time.to_i}.html" + expect(File.exist?(profile_path)).to be true + end + + after do + Gitlab::RequestProfiler.remove_all_profiles + end + end + + context "when user is logged-in" do + before do + login_as(user) + end + + include_examples 'profiling a request' + end + + context "when user is not logged-in" do + include_examples 'profiling a request' + end +end |