diff options
Diffstat (limited to 'spec/controllers/projects')
18 files changed, 844 insertions, 147 deletions
diff --git a/spec/controllers/projects/avatars_controller_spec.rb b/spec/controllers/projects/avatars_controller_spec.rb index 14059cff74c..5a77a7ac06f 100644 --- a/spec/controllers/projects/avatars_controller_spec.rb +++ b/spec/controllers/projects/avatars_controller_spec.rb @@ -26,12 +26,37 @@ describe Projects::AvatarsController do context 'when the avatar is stored in the repository' do let(:filepath) { 'files/images/logo-white.png' } - it 'sends the avatar' do - subject + context 'when feature flag workhorse_set_content_type is' do + before do + stub_feature_flags(workhorse_set_content_type: flag_value) + end - expect(response).to have_gitlab_http_status(200) - expect(response.header['Content-Type']).to eq('image/png') - expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:') + context 'enabled' do + let(:flag_value) { true } + + it 'sends the avatar' do + subject + + expect(response).to have_gitlab_http_status(200) + expect(response.header['Content-Disposition']).to eq('inline') + expect(response.header['Content-Type']).to eq 'image/png' + expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:') + expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true" + end + end + + context 'disabled' do + let(:flag_value) { false } + + it 'sends the avatar' do + subject + + expect(response).to have_gitlab_http_status(200) + expect(response.header['Content-Type']).to eq('image/png') + expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:') + expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq nil + end + end end end diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb index 5fdf7f1229d..9fc6af6a045 100644 --- a/spec/controllers/projects/blob_controller_spec.rb +++ b/spec/controllers/projects/blob_controller_spec.rb @@ -35,6 +35,11 @@ describe Projects::BlobController do let(:id) { 'binary-encoding/encoding/binary-1.bin' } it { is_expected.to respond_with(:success) } end + + context "Markdown file" do + let(:id) { 'master/README.md' } + it { is_expected.to respond_with(:success) } + end end context 'with file path and JSON format' do @@ -152,7 +157,7 @@ describe Projects::BlobController do expect(match_line['meta_data']).to have_key('new_pos') end - it 'does not add top match line when when "since" is equal 1' do + it 'does not add top match line when "since" is equal 1' do do_get(since: 1, to: 10, offset: 10, from_merge_request: true) match_line = JSON.parse(response.body).first diff --git a/spec/controllers/projects/commits_controller_spec.rb b/spec/controllers/projects/commits_controller_spec.rb index a43bdd3ea80..80513650636 100644 --- a/spec/controllers/projects/commits_controller_spec.rb +++ b/spec/controllers/projects/commits_controller_spec.rb @@ -5,87 +5,145 @@ describe Projects::CommitsController do let(:user) { create(:user) } before do - sign_in(user) project.add_maintainer(user) end - describe "GET commits_root" do - context "no ref is provided" do - it 'should redirect to the default branch of the project' do - get(:commits_root, - namespace_id: project.namespace, - project_id: project) + context 'signed in' do + before do + sign_in(user) + end + + describe "GET commits_root" do + context "no ref is provided" do + it 'should redirect to the default branch of the project' do + get(:commits_root, + namespace_id: project.namespace, + project_id: project) - expect(response).to redirect_to project_commits_path(project) + expect(response).to redirect_to project_commits_path(project) + end end end - end - describe "GET show" do - render_views + describe "GET show" do + render_views + + context 'with file path' do + before do + get(:show, + namespace_id: project.namespace, + project_id: project, + id: id) + end + + context "valid branch, valid file" do + let(:id) { 'master/README.md' } + + it { is_expected.to respond_with(:success) } + end + + context "valid branch, invalid file" do + let(:id) { 'master/invalid-path.rb' } + + it { is_expected.to respond_with(:not_found) } + end + + context "invalid branch, valid file" do + let(:id) { 'invalid-branch/README.md' } + + it { is_expected.to respond_with(:not_found) } + end + + context "branch with invalid format, valid file" do + let(:id) { 'branch with space/README.md' } + + it { is_expected.to respond_with(:not_found) } + end + end + + context "when the ref name ends in .atom" do + context "when the ref does not exist with the suffix" do + before do + get(:show, + namespace_id: project.namespace, + project_id: project, + id: "master.atom") + end + + it "renders as atom" do + expect(response).to be_success + expect(response.content_type).to eq('application/atom+xml') + end + + it 'renders summary with type=html' do + expect(response.body).to include('<summary type="html">') + end + end + + context "when the ref exists with the suffix" do + before do + commit = project.repository.commit('master') + + allow_any_instance_of(Repository).to receive(:commit).and_call_original + allow_any_instance_of(Repository).to receive(:commit).with('master.atom').and_return(commit) + + get(:show, + namespace_id: project.namespace, + project_id: project, + id: "master.atom") + end + + it "renders as HTML" do + expect(response).to be_success + expect(response.content_type).to eq('text/html') + end + end + end + end + + describe "GET /commits/:id/signatures" do + render_views - context 'with file path' do before do - get(:show, + get(:signatures, namespace_id: project.namespace, project_id: project, - id: id) + id: id, + format: :json) end - context "valid branch, valid file" do - let(:id) { 'master/README.md' } + context "valid branch" do + let(:id) { 'master' } it { is_expected.to respond_with(:success) } end - context "valid branch, invalid file" do - let(:id) { 'master/invalid-path.rb' } - - it { is_expected.to respond_with(:not_found) } - end - - context "invalid branch, valid file" do - let(:id) { 'invalid-branch/README.md' } + context "invalid branch format" do + let(:id) { 'some branch' } it { is_expected.to respond_with(:not_found) } end end + end - context "when the ref name ends in .atom" do - context "when the ref does not exist with the suffix" do + context 'token authentication' do + context 'public project' do + it_behaves_like 'authenticates sessionless user', :show, :atom, public: true do before do - get(:show, - namespace_id: project.namespace, - project_id: project, - id: "master.atom") - end + public_project = create(:project, :repository, :public) - it "renders as atom" do - expect(response).to be_success - expect(response.content_type).to eq('application/atom+xml') - end - - it 'renders summary with type=html' do - expect(response.body).to include('<summary type="html">') + default_params.merge!(namespace_id: public_project.namespace, project_id: public_project, id: "master.atom") end end + end - context "when the ref exists with the suffix" do + context 'private project' do + it_behaves_like 'authenticates sessionless user', :show, :atom, public: false do before do - commit = project.repository.commit('master') - - allow_any_instance_of(Repository).to receive(:commit).and_call_original - allow_any_instance_of(Repository).to receive(:commit).with('master.atom').and_return(commit) - - get(:show, - namespace_id: project.namespace, - project_id: project, - id: "master.atom") - end + private_project = create(:project, :repository, :private) + private_project.add_maintainer(user) - it "renders as HTML" do - expect(response).to be_success - expect(response.content_type).to eq('text/html') + default_params.merge!(namespace_id: private_project.namespace, project_id: private_project, id: "master.atom") end end end diff --git a/spec/controllers/projects/deploy_keys_controller_spec.rb b/spec/controllers/projects/deploy_keys_controller_spec.rb index 73bf169085f..4567a51b88e 100644 --- a/spec/controllers/projects/deploy_keys_controller_spec.rb +++ b/spec/controllers/projects/deploy_keys_controller_spec.rb @@ -27,12 +27,8 @@ describe Projects::DeployKeysController do let(:project2) { create(:project, :internal)} let(:project_private) { create(:project, :private)} - let(:deploy_key_internal) do - create(:deploy_key, key: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCdMHEHyhRjbhEZVddFn6lTWdgEy5Q6Bz4nwGB76xWZI5YT/1WJOMEW+sL5zYd31kk7sd3FJ5L9ft8zWMWrr/iWXQikC2cqZK24H1xy+ZUmrRuJD4qGAaIVoyyzBL+avL+lF8J5lg6YSw8gwJY/lX64/vnJHUlWw2n5BF8IFOWhiw== dummy@gitlab.com') - end - let(:deploy_key_actual) do - create(:deploy_key, key: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDNd/UJWhPrpb+b/G5oL109y57yKuCxE+WUGJGYaj7WQKsYRJmLYh1mgjrl+KVyfsWpq4ylOxIfFSnN9xBBFN8mlb0Fma5DC7YsSsibJr3MZ19ZNBprwNcdogET7aW9I0In7Wu5f2KqI6e5W/spJHCy4JVxzVMUvk6Myab0LnJ2iQ== dummy@gitlab.com') - end + let(:deploy_key_internal) { create(:deploy_key) } + let(:deploy_key_actual) { create(:deploy_key) } let!(:deploy_key_public) { create(:deploy_key, public: true) } let!(:deploy_keys_project_internal) do @@ -63,4 +59,145 @@ describe Projects::DeployKeysController do end end end + + describe '/enable/:id' do + let(:deploy_key) { create(:deploy_key) } + let(:project2) { create(:project) } + let!(:deploy_keys_project_internal) do + create(:deploy_keys_project, project: project2, deploy_key: deploy_key) + end + + context 'with anonymous user' do + before do + sign_out(:user) + end + + it 'redirects to login' do + expect do + put :enable, id: deploy_key.id, namespace_id: project.namespace, project_id: project + end.not_to change { DeployKeysProject.count } + + expect(response).to have_http_status(302) + expect(response).to redirect_to(new_user_session_path) + end + end + + context 'with user with no permission' do + before do + sign_in(create(:user)) + end + + it 'returns 404' do + expect do + put :enable, id: deploy_key.id, namespace_id: project.namespace, project_id: project + end.not_to change { DeployKeysProject.count } + + expect(response).to have_http_status(404) + end + end + + context 'with user with permission' do + before do + project2.add_maintainer(user) + end + + it 'returns 302' do + expect do + put :enable, id: deploy_key.id, namespace_id: project.namespace, project_id: project + end.to change { DeployKeysProject.count }.by(1) + + expect(DeployKeysProject.where(project_id: project.id, deploy_key_id: deploy_key.id).count).to eq(1) + expect(response).to have_http_status(302) + expect(response).to redirect_to(namespace_project_settings_repository_path(anchor: 'js-deploy-keys-settings')) + end + + it 'returns 404' do + put :enable, id: 0, namespace_id: project.namespace, project_id: project + + expect(response).to have_http_status(404) + end + end + + context 'with admin' do + before do + sign_in(create(:admin)) + end + + it 'returns 302' do + expect do + put :enable, id: deploy_key.id, namespace_id: project.namespace, project_id: project + end.to change { DeployKeysProject.count }.by(1) + + expect(DeployKeysProject.where(project_id: project.id, deploy_key_id: deploy_key.id).count).to eq(1) + expect(response).to have_http_status(302) + expect(response).to redirect_to(namespace_project_settings_repository_path(anchor: 'js-deploy-keys-settings')) + end + end + end + + describe '/disable/:id' do + let(:deploy_key) { create(:deploy_key) } + let!(:deploy_key_project) { create(:deploy_keys_project, project: project, deploy_key: deploy_key) } + + context 'with anonymous user' do + before do + sign_out(:user) + end + + it 'redirects to login' do + put :disable, id: deploy_key.id, namespace_id: project.namespace, project_id: project + + expect(response).to have_http_status(302) + expect(response).to redirect_to(new_user_session_path) + expect(DeployKey.find(deploy_key.id)).to eq(deploy_key) + end + end + + context 'with user with no permission' do + before do + sign_in(create(:user)) + end + + it 'returns 404' do + put :disable, id: deploy_key.id, namespace_id: project.namespace, project_id: project + + expect(response).to have_http_status(404) + expect(DeployKey.find(deploy_key.id)).to eq(deploy_key) + end + end + + context 'with user with permission' do + it 'returns 302' do + put :disable, id: deploy_key.id, namespace_id: project.namespace, project_id: project + + expect(response).to have_http_status(302) + expect(response).to redirect_to(namespace_project_settings_repository_path(anchor: 'js-deploy-keys-settings')) + + expect { DeployKey.find(deploy_key.id) }.to raise_error(ActiveRecord::RecordNotFound) + end + + it 'returns 404' do + put :disable, id: 0, namespace_id: project.namespace, project_id: project + + expect(response).to have_http_status(404) + end + end + + context 'with admin' do + before do + sign_in(create(:admin)) + end + + it 'returns 302' do + expect do + put :disable, id: deploy_key.id, namespace_id: project.namespace, project_id: project + end.to change { DeployKey.count }.by(-1) + + expect(response).to have_http_status(302) + expect(response).to redirect_to(namespace_project_settings_repository_path(anchor: 'js-deploy-keys-settings')) + + expect { DeployKey.find(deploy_key.id) }.to raise_error(ActiveRecord::RecordNotFound) + end + end + end end diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb index bc17331f531..5fa0488014f 100644 --- a/spec/controllers/projects/environments_controller_spec.rb +++ b/spec/controllers/projects/environments_controller_spec.rb @@ -217,7 +217,10 @@ describe Projects::EnvironmentsController do end it 'loads the terminals for the environment' do - expect_any_instance_of(Environment).to receive(:terminals) + # In EE we have to stub EE::Environment since it overwrites the + # "terminals" method. + expect_any_instance_of(defined?(EE) ? EE::Environment : Environment) + .to receive(:terminals) get :terminal, environment_params end @@ -240,7 +243,9 @@ describe Projects::EnvironmentsController do context 'and valid id' do it 'returns the first terminal for the environment' do - expect_any_instance_of(Environment) + # In EE we have to stub EE::Environment since it overwrites the + # "terminals" method. + expect_any_instance_of(defined?(EE) ? EE::Environment : Environment) .to receive(:terminals) .and_return([:fake_terminal]) diff --git a/spec/controllers/projects/imports_controller_spec.rb b/spec/controllers/projects/imports_controller_spec.rb index adf3c78ae51..cdc63f5aab3 100644 --- a/spec/controllers/projects/imports_controller_spec.rb +++ b/spec/controllers/projects/imports_controller_spec.rb @@ -26,10 +26,11 @@ describe Projects::ImportsController do context 'when repository exists' do let(:project) { create(:project_empty_repo, import_url: 'https://github.com/vim/vim.git') } + let(:import_state) { project.import_state } context 'when import is in progress' do before do - project.update(import_status: :started) + import_state.update(status: :started) end it 'renders template' do @@ -47,7 +48,7 @@ describe Projects::ImportsController do context 'when import failed' do before do - project.update(import_status: :failed) + import_state.update(status: :failed) end it 'redirects to new_namespace_project_import_path' do @@ -59,7 +60,7 @@ describe Projects::ImportsController do context 'when import finished' do before do - project.update(import_status: :finished) + import_state.update(status: :finished) end context 'when project is a fork' do @@ -108,7 +109,7 @@ describe Projects::ImportsController do context 'when import never happened' do before do - project.update(import_status: :none) + import_state.update(status: :none) end it 'redirects to namespace_project_path' do diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index 80138183c07..02930edbf72 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -1068,4 +1068,40 @@ describe Projects::IssuesController do end end end + + context 'private project with token authentication' do + let(:private_project) { create(:project, :private) } + + it_behaves_like 'authenticates sessionless user', :index, :atom do + before do + default_params.merge!(project_id: private_project, namespace_id: private_project.namespace) + + private_project.add_maintainer(user) + end + end + + it_behaves_like 'authenticates sessionless user', :calendar, :ics do + before do + default_params.merge!(project_id: private_project, namespace_id: private_project.namespace) + + private_project.add_maintainer(user) + end + end + end + + context 'public project with token authentication' do + let(:public_project) { create(:project, :public) } + + it_behaves_like 'authenticates sessionless user', :index, :atom, public: true do + before do + default_params.merge!(project_id: public_project, namespace_id: public_project.namespace) + end + end + + it_behaves_like 'authenticates sessionless user', :calendar, :ics, public: true do + before do + default_params.merge!(project_id: public_project, namespace_id: public_project.namespace) + end + end + end end diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb index da3d658d061..fca313dafb1 100644 --- a/spec/controllers/projects/jobs_controller_spec.rb +++ b/spec/controllers/projects/jobs_controller_spec.rb @@ -401,18 +401,56 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do context 'with variables' do before do create(:ci_pipeline_variable, pipeline: pipeline, key: :TRIGGER_KEY_1, value: 'TRIGGER_VALUE_1') + end - get_show(id: job.id, format: :json) + context 'user is a maintainer' do + before do + project.add_maintainer(user) + + get_show(id: job.id, format: :json) + end + + it 'returns a job_detail' do + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('job/job_details') + end + + it 'exposes trigger information and variables' do + expect(json_response['trigger']['short_token']).to eq 'toke' + expect(json_response['trigger']['variables'].length).to eq 1 + end + + it 'exposes correct variable properties' do + first_variable = json_response['trigger']['variables'].first + + expect(first_variable['key']).to eq "TRIGGER_KEY_1" + expect(first_variable['value']).to eq "TRIGGER_VALUE_1" + expect(first_variable['public']).to eq false + end end - it 'exposes trigger information and variables' do - expect(response).to have_gitlab_http_status(:ok) - expect(response).to match_response_schema('job/job_details') - expect(json_response['trigger']['short_token']).to eq 'toke' - expect(json_response['trigger']['variables'].length).to eq 1 - expect(json_response['trigger']['variables'].first['key']).to eq "TRIGGER_KEY_1" - expect(json_response['trigger']['variables'].first['value']).to eq "TRIGGER_VALUE_1" - expect(json_response['trigger']['variables'].first['public']).to eq false + context 'user is not a mantainer' do + before do + get_show(id: job.id, format: :json) + end + + it 'returns a job_detail' do + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('job/job_details') + end + + it 'exposes trigger information and variables' do + expect(json_response['trigger']['short_token']).to eq 'toke' + expect(json_response['trigger']['variables'].length).to eq 1 + end + + it 'exposes correct variable properties' do + first_variable = json_response['trigger']['variables'].first + + expect(first_variable['key']).to eq "TRIGGER_KEY_1" + expect(first_variable['value']).to be_nil + expect(first_variable['public']).to eq false + end end end end @@ -838,23 +876,48 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do context "when job has a trace artifact" do let(:job) { create(:ci_build, :trace_artifact, pipeline: pipeline) } - it 'returns a trace' do - response = subject + context 'when feature flag workhorse_set_content_type is' do + before do + stub_feature_flags(workhorse_set_content_type: flag_value) + end - expect(response).to have_gitlab_http_status(:ok) - expect(response.headers["Content-Type"]).to eq("text/plain; charset=utf-8") - expect(response.body).to eq(job.job_artifacts_trace.open.read) + context 'enabled' do + let(:flag_value) { true } + + it "sets #{Gitlab::Workhorse::DETECT_HEADER} header" do + response = subject + + expect(response).to have_gitlab_http_status(:ok) + expect(response.headers["Content-Type"]).to eq("text/plain; charset=utf-8") + expect(response.body).to eq(job.job_artifacts_trace.open.read) + expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true" + end + end + + context 'disabled' do + let(:flag_value) { false } + + it 'returns a trace' do + response = subject + + expect(response).to have_gitlab_http_status(:ok) + expect(response.headers["Content-Type"]).to eq("text/plain; charset=utf-8") + expect(response.body).to eq(job.job_artifacts_trace.open.read) + expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to be nil + end + end end end context "when job has a trace file" do let(:job) { create(:ci_build, :trace_live, pipeline: pipeline) } - it "send a trace file" do + it 'sends a trace file' do response = subject expect(response).to have_gitlab_http_status(:ok) expect(response.headers["Content-Type"]).to eq("text/plain; charset=utf-8") + expect(response.headers["Content-Disposition"]).to match(/^inline/) expect(response.body).to eq("BUILD TRACE") end end @@ -866,12 +929,27 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do job.update_column(:trace, "Sample trace") end - it "send a trace file" do + it 'sends a trace file' do response = subject expect(response).to have_gitlab_http_status(:ok) - expect(response.headers["Content-Type"]).to eq("text/plain; charset=utf-8") - expect(response.body).to eq("Sample trace") + expect(response.headers['Content-Type']).to eq('text/plain; charset=utf-8') + expect(response.headers['Content-Disposition']).to match(/^inline/) + expect(response.body).to eq('Sample trace') + end + + context 'when trace format is not text/plain' do + before do + job.update_column(:trace, '<html></html>') + end + + it 'sets content disposition to attachment' do + response = subject + + expect(response).to have_gitlab_http_status(:ok) + expect(response.headers['Content-Type']).to eq('text/plain; charset=utf-8') + expect(response.headers['Content-Disposition']).to match(/^attachment/) + end end end diff --git a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb index 9dc06436c72..8fc5d302af6 100644 --- a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb @@ -36,6 +36,18 @@ describe Projects::MergeRequests::DiffsController do end end + context 'when note has no position' do + before do + create(:legacy_diff_note_on_merge_request, project: project, noteable: merge_request, position: nil) + end + + it 'serializes merge request diff collection' do + expect_any_instance_of(DiffsSerializer).to receive(:represent).with(an_instance_of(Gitlab::Diff::FileCollection::MergeRequestDiff), an_instance_of(Hash)) + + go + end + end + context 'with forked projects with submodules' do render_views diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index e62523c65c9..7f15da859e5 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -290,6 +290,20 @@ describe Projects::MergeRequestsController do it_behaves_like 'update invalid issuable', MergeRequest end + + context 'two merge requests with the same source branch' do + it 'does not allow a closed merge request to be reopened if another one is open' do + merge_request.close! + create(:merge_request, source_project: merge_request.source_project, source_branch: merge_request.source_branch) + + update_merge_request(state_event: 'reopen') + + errors = assigns[:merge_request].errors + + expect(errors[:validate_branches]).to include(/Another open merge request already exists for this source branch/) + expect(merge_request.reload).to be_closed + end + end end describe 'POST merge' do diff --git a/spec/controllers/projects/milestones_controller_spec.rb b/spec/controllers/projects/milestones_controller_spec.rb index ccd4fc4db3a..658aa2a6738 100644 --- a/spec/controllers/projects/milestones_controller_spec.rb +++ b/spec/controllers/projects/milestones_controller_spec.rb @@ -143,11 +143,27 @@ describe Projects::MilestonesController do end describe '#promote' do + let(:group) { create(:group) } + + before do + project.update(namespace: group) + end + + context 'when user does not have permission to promote milestone' do + before do + group.add_guest(user) + end + + it 'renders 404' do + post :promote, namespace_id: project.namespace.id, project_id: project.id, id: milestone.iid + + expect(response).to have_gitlab_http_status(404) + end + end + context 'promotion succeeds' do before do - group = create(:group) group.add_developer(user) - milestone.project.update(namespace: group) end it 'shows group milestone' do @@ -166,12 +182,17 @@ describe Projects::MilestonesController do end end - context 'promotion fails' do - it 'shows project milestone' do + context 'when user cannot admin group milestones' do + before do + project.add_developer(user) + end + + it 'renders 404' do + project.update(namespace: user.namespace) + post :promote, namespace_id: project.namespace.id, project_id: project.id, id: milestone.iid - expect(response).to redirect_to(project_milestone_path(project, milestone)) - expect(flash[:alert]).to eq('Promotion failed - Project does not belong to a group.') + expect(response).to have_gitlab_http_status(404) end end end diff --git a/spec/controllers/projects/mirrors_controller_spec.rb b/spec/controllers/projects/mirrors_controller_spec.rb index 00c1e617e3a..976f480930c 100644 --- a/spec/controllers/projects/mirrors_controller_spec.rb +++ b/spec/controllers/projects/mirrors_controller_spec.rb @@ -15,6 +15,31 @@ describe Projects::MirrorsController do end.to change { RemoteMirror.count }.to(1) end end + + context 'setting up SSH public-key authentication' do + let(:ssh_mirror_attributes) do + { + 'auth_method' => 'ssh_public_key', + 'url' => 'ssh://git@example.com', + 'ssh_known_hosts' => 'test' + } + end + + it 'processes a successful update' do + sign_in(project.owner) + do_put(project, remote_mirrors_attributes: { '0' => ssh_mirror_attributes }) + + expect(response).to redirect_to(project_settings_repository_path(project, anchor: 'js-push-remote-settings')) + + expect(RemoteMirror.count).to eq(1) + expect(RemoteMirror.first).to have_attributes( + auth_method: 'ssh_public_key', + url: 'ssh://git@example.com', + ssh_public_key: match(/\Assh-rsa /), + ssh_known_hosts: 'test' + ) + end + end end describe '#update' do diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb index 9ac7b8ee8a8..d2a26068362 100644 --- a/spec/controllers/projects/notes_controller_spec.rb +++ b/spec/controllers/projects/notes_controller_spec.rb @@ -283,14 +283,14 @@ describe Projects::NotesController do def post_create(extra_params = {}) post :create, { - note: { note: 'some other note' }, - namespace_id: project.namespace, - project_id: project, - target_type: 'merge_request', - target_id: merge_request.id, - note_project_id: forked_project.id, - in_reply_to_discussion_id: existing_comment.discussion_id - }.merge(extra_params) + note: { note: 'some other note', noteable_id: merge_request.id }, + namespace_id: project.namespace, + project_id: project, + target_type: 'merge_request', + target_id: merge_request.id, + note_project_id: forked_project.id, + in_reply_to_discussion_id: existing_comment.discussion_id + }.merge(extra_params) end context 'when the note_project_id is not correct' do @@ -324,6 +324,30 @@ describe Projects::NotesController do end end + context 'when target_id and noteable_id do not match' do + let(:locked_issue) { create(:issue, :locked, project: project) } + let(:issue) {create(:issue, project: project)} + + before do + project.update_attribute(:visibility_level, Gitlab::VisibilityLevel::PUBLIC) + project.project_member(user).destroy + end + + it 'uses target_id and ignores noteable_id' do + request_params = { + note: { note: 'some note', noteable_type: 'Issue', noteable_id: locked_issue.id }, + target_type: 'issue', + target_id: issue.id, + project_id: project, + namespace_id: project.namespace + } + + expect { post :create, request_params }.to change { issue.notes.count }.by(1) + .and change { locked_issue.notes.count }.by(0) + expect(response).to have_gitlab_http_status(302) + end + end + context 'when the merge request discussion is locked' do before do project.update_attribute(:visibility_level, Gitlab::VisibilityLevel::PUBLIC) @@ -376,35 +400,60 @@ describe Projects::NotesController do end describe 'PUT update' do - let(:request_params) do - { - namespace_id: project.namespace, - project_id: project, - id: note, - format: :json, - note: { - note: "New comment" + context "should update the note with a valid issue" do + let(:request_params) do + { + namespace_id: project.namespace, + project_id: project, + id: note, + format: :json, + note: { + note: "New comment" + } } - } - end + end - before do - sign_in(note.author) - project.add_developer(note.author) + before do + sign_in(note.author) + project.add_developer(note.author) + end + + it "updates the note" do + expect { put :update, request_params }.to change { note.reload.note } + end end + context "doesnt update the note" do + let(:issue) { create(:issue, :confidential, project: project) } + let(:note) { create(:note, noteable: issue, project: project) } - it "updates the note" do - expect { put :update, request_params }.to change { note.reload.note } + before do + sign_in(user) + project.add_guest(user) + end + + it "disallows edits when the issue is confidential and the user has guest permissions" do + request_params = { + namespace_id: project.namespace, + project_id: project, + id: note, + format: :json, + note: { + note: "New comment" + } + } + expect { put :update, request_params }.not_to change { note.reload.note } + expect(response).to have_gitlab_http_status(404) + end end end describe 'DELETE destroy' do let(:request_params) do { - namespace_id: project.namespace, - project_id: project, - id: note, - format: :js + namespace_id: project.namespace, + project_id: project, + id: note, + format: :js } end diff --git a/spec/controllers/projects/raw_controller_spec.rb b/spec/controllers/projects/raw_controller_spec.rb index 6b658bf5295..d3cd15fbcd7 100644 --- a/spec/controllers/projects/raw_controller_spec.rb +++ b/spec/controllers/projects/raw_controller_spec.rb @@ -14,26 +14,74 @@ describe Projects::RawController do context 'regular filename' do let(:filepath) { 'master/README.md' } - it 'delivers ASCII file' do - subject - - expect(response).to have_gitlab_http_status(200) - expect(response.header['Content-Type']).to eq('text/plain; charset=utf-8') - expect(response.header['Content-Disposition']) - .to eq('inline') - expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:') + context 'when feature flag workhorse_set_content_type is' do + before do + stub_feature_flags(workhorse_set_content_type: flag_value) + + subject + end + + context 'enabled' do + let(:flag_value) { true } + + it 'delivers ASCII file' do + expect(response).to have_gitlab_http_status(200) + expect(response.header['Content-Type']).to eq('text/plain; charset=utf-8') + expect(response.header['Content-Disposition']).to eq('inline') + expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true" + expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:') + end + end + + context 'disabled' do + let(:flag_value) { false } + + it 'delivers ASCII file' do + expect(response).to have_gitlab_http_status(200) + expect(response.header['Content-Type']).to eq('text/plain; charset=utf-8') + expect(response.header['Content-Disposition']).to eq('inline') + expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq nil + expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:') + end + end end end context 'image header' do let(:filepath) { 'master/files/images/6049019_460s.jpg' } - it 'sets image content type header' do - subject + context 'when feature flag workhorse_set_content_type is' do + before do + stub_feature_flags(workhorse_set_content_type: flag_value) + end + + context 'enabled' do + let(:flag_value) { true } + + it 'leaves image content disposition' do + subject + + expect(response).to have_gitlab_http_status(200) + expect(response.header['Content-Type']).to eq('image/jpeg') + expect(response.header['Content-Disposition']).to eq('inline') + expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true" + expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:') + end + end + + context 'disabled' do + let(:flag_value) { false } + + it 'sets image content type header' do + subject - expect(response).to have_gitlab_http_status(200) - expect(response.header['Content-Type']).to eq('image/jpeg') - expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:') + expect(response).to have_gitlab_http_status(200) + expect(response.header['Content-Type']).to eq('image/jpeg') + expect(response.header['Content-Disposition']).to eq('inline') + expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq nil + expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:') + end + end end end diff --git a/spec/controllers/projects/serverless/functions_controller_spec.rb b/spec/controllers/projects/serverless/functions_controller_spec.rb new file mode 100644 index 00000000000..284b582b1f5 --- /dev/null +++ b/spec/controllers/projects/serverless/functions_controller_spec.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Projects::Serverless::FunctionsController do + include KubernetesHelpers + include ReactiveCachingHelpers + + let(:user) { create(:user) } + let(:cluster) { create(:cluster, :project, :provided_by_gcp) } + let(:knative) { create(:clusters_applications_knative, :installed, cluster: cluster) } + let(:service) { cluster.platform_kubernetes } + let(:project) { cluster.project} + + let(:namespace) do + create(:cluster_kubernetes_namespace, + cluster: cluster, + cluster_project: cluster.cluster_project, + project: cluster.cluster_project.project) + end + + before do + project.add_maintainer(user) + sign_in(user) + end + + def params(opts = {}) + opts.reverse_merge(namespace_id: project.namespace.to_param, + project_id: project.to_param) + end + + describe 'GET #index' do + context 'empty cache' do + it 'has no data' do + get :index, params({ format: :json }) + + expect(response).to have_gitlab_http_status(204) + end + + it 'renders an html page' do + get :index, params + + expect(response).to have_gitlab_http_status(200) + end + end + end + + describe 'GET #index with data', :use_clean_rails_memory_store_caching do + before do + stub_reactive_cache(knative, services: kube_knative_services_body(namespace: namespace.namespace, name: cluster.project.name)["items"]) + end + + it 'has data' do + get :index, params({ format: :json }) + + expect(response).to have_gitlab_http_status(200) + + expect(json_response).to contain_exactly( + a_hash_including( + "name" => project.name, + "url" => "http://#{project.name}.#{namespace.namespace}.example.com" + ) + ) + end + + it 'has data in html' do + get :index, params + + expect(response).to have_gitlab_http_status(200) + end + end +end diff --git a/spec/controllers/projects/settings/repository_controller_spec.rb b/spec/controllers/projects/settings/repository_controller_spec.rb index 9cee40b7553..70f79a47e63 100644 --- a/spec/controllers/projects/settings/repository_controller_spec.rb +++ b/spec/controllers/projects/settings/repository_controller_spec.rb @@ -17,4 +17,37 @@ describe Projects::Settings::RepositoryController do expect(response).to render_template(:show) end end + + describe 'PUT cleanup' do + before do + allow(RepositoryCleanupWorker).to receive(:perform_async) + end + + def do_put! + object_map = fixture_file_upload('spec/fixtures/bfg_object_map.txt') + + put :cleanup, namespace_id: project.namespace, project_id: project, project: { object_map: object_map } + end + + context 'feature enabled' do + it 'enqueues a RepositoryCleanupWorker' do + stub_feature_flags(project_cleanup: true) + + do_put! + + expect(response).to redirect_to project_settings_repository_path(project) + expect(RepositoryCleanupWorker).to have_received(:perform_async).once + end + end + + context 'feature disabled' do + it 'shows a 404 error' do + stub_feature_flags(project_cleanup: false) + + do_put! + + expect(response).to have_gitlab_http_status(404) + end + end + end end diff --git a/spec/controllers/projects/tags_controller_spec.rb b/spec/controllers/projects/tags_controller_spec.rb index c48f41ca12e..6fbf75d0259 100644 --- a/spec/controllers/projects/tags_controller_spec.rb +++ b/spec/controllers/projects/tags_controller_spec.rb @@ -35,4 +35,26 @@ describe Projects::TagsController do it { is_expected.to respond_with(:not_found) } end end + + context 'private project with token authentication' do + let(:private_project) { create(:project, :repository, :private) } + + it_behaves_like 'authenticates sessionless user', :index, :atom do + before do + default_params.merge!(project_id: private_project, namespace_id: private_project.namespace) + + private_project.add_maintainer(user) + end + end + end + + context 'public project with token authentication' do + let(:public_project) { create(:project, :repository, :public) } + + it_behaves_like 'authenticates sessionless user', :index, :atom, public: true do + before do + default_params.merge!(project_id: public_project, namespace_id: public_project.namespace) + end + end + end end diff --git a/spec/controllers/projects/wikis_controller_spec.rb b/spec/controllers/projects/wikis_controller_spec.rb index 6d75152857b..b974d927856 100644 --- a/spec/controllers/projects/wikis_controller_spec.rb +++ b/spec/controllers/projects/wikis_controller_spec.rb @@ -52,24 +52,56 @@ describe Projects::WikisController do let(:path) { upload_file_to_wiki(project, user, file_name) } - before do - subject - end - subject { get :show, namespace_id: project.namespace, project_id: project, id: path } context 'when file is an image' do let(:file_name) { 'dk.png' } - it 'renders the content inline' do - expect(response.headers['Content-Disposition']).to match(/^inline/) - end + context 'when feature flag workhorse_set_content_type is' do + before do + stub_feature_flags(workhorse_set_content_type: flag_value) + + subject + end - context 'when file is a svg' do - let(:file_name) { 'unsanitized.svg' } + context 'enabled' do + let(:flag_value) { true } - it 'renders the content as an attachment' do - expect(response.headers['Content-Disposition']).to match(/^attachment/) + it 'delivers the image' do + expect(response.headers['Content-Type']).to eq('image/png') + expect(response.headers['Content-Disposition']).to match(/^inline/) + expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq "true" + end + + context 'when file is a svg' do + let(:file_name) { 'unsanitized.svg' } + + it 'delivers the image' do + expect(response.headers['Content-Type']).to eq('image/svg+xml') + expect(response.headers['Content-Disposition']).to match(/^attachment/) + expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq "true" + end + end + end + + context 'disabled' do + let(:flag_value) { false } + + it 'renders the content inline' do + expect(response.headers['Content-Type']).to eq('image/png') + expect(response.headers['Content-Disposition']).to match(/^inline/) + expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq nil + end + + context 'when file is a svg' do + let(:file_name) { 'unsanitized.svg' } + + it 'renders the content as an attachment' do + expect(response.headers['Content-Type']).to eq('image/svg+xml') + expect(response.headers['Content-Disposition']).to match(/^attachment/) + expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq nil + end + end end end end @@ -77,8 +109,32 @@ describe Projects::WikisController do context 'when file is a pdf' do let(:file_name) { 'git-cheat-sheet.pdf' } - it 'sets the content type to application/octet-stream' do - expect(response.headers['Content-Type']).to eq 'application/octet-stream' + context 'when feature flag workhorse_set_content_type is' do + before do + stub_feature_flags(workhorse_set_content_type: flag_value) + + subject + end + + context 'enabled' do + let(:flag_value) { true } + + it 'sets the content type to sets the content response headers' do + expect(response.headers['Content-Type']).to eq 'application/octet-stream' + expect(response.headers['Content-Disposition']).to match(/^inline/) + expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq "true" + end + end + + context 'disabled' do + let(:flag_value) { false } + + it 'sets the content response headers' do + expect(response.headers['Content-Type']).to eq 'application/octet-stream' + expect(response.headers['Content-Disposition']).to match(/^inline/) + expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq nil + end + end end end end |