diff options
author | jhampton <jhampton@gitlab.com> | 2018-12-07 21:21:43 +0300 |
---|---|---|
committer | jhampton <jhampton@gitlab.com> | 2018-12-07 21:21:43 +0300 |
commit | 6de31cddb81613045ae4ac920a054c53f2028949 (patch) | |
tree | 5da9d29ba985e9ce2b81f02c33fd43b222e91e10 /spec/controllers | |
parent | 02ef0523634123f3abc3dd6235ff229e38f40341 (diff) | |
parent | 88c0984d077e2a85d684d71d036d27278cd81182 (diff) |
Merge remote-tracking branch 'origin/master' into 20422-hide-ui-variables-by-default
Diffstat (limited to 'spec/controllers')
30 files changed, 797 insertions, 308 deletions
diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb index f350641a643..3dd0b2623ac 100644 --- a/spec/controllers/admin/users_controller_spec.rb +++ b/spec/controllers/admin/users_controller_spec.rb @@ -264,5 +264,17 @@ describe Admin::UsersController do expect(flash[:alert]).to eq("You are now impersonating #{user.username}") end end + + context "when impersonation is disabled" do + before do + stub_config_setting(impersonation_enabled: false) + end + + it "shows error page" do + post :impersonate, id: user.username + + expect(response).to have_gitlab_http_status(404) + end + end end end diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index efc3ce74627..c2bd7fd9808 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -107,59 +107,6 @@ describe ApplicationController do end end - describe "#authenticate_user_from_personal_access_token!" do - before do - stub_authentication_activity_metrics(debug: false) - end - - controller(described_class) do - def index - render text: 'authenticated' - end - end - - let(:personal_access_token) { create(:personal_access_token, user: user) } - - context "when the 'personal_access_token' param is populated with the personal access token" do - it "logs the user in" do - expect(authentication_metrics) - .to increment(:user_authenticated_counter) - .and increment(:user_session_override_counter) - .and increment(:user_sessionless_authentication_counter) - - get :index, private_token: personal_access_token.token - - expect(response).to have_gitlab_http_status(200) - expect(response.body).to eq('authenticated') - end - end - - context "when the 'PERSONAL_ACCESS_TOKEN' header is populated with the personal access token" do - it "logs the user in" do - expect(authentication_metrics) - .to increment(:user_authenticated_counter) - .and increment(:user_session_override_counter) - .and increment(:user_sessionless_authentication_counter) - - @request.headers["PRIVATE-TOKEN"] = personal_access_token.token - get :index - - expect(response).to have_gitlab_http_status(200) - expect(response.body).to eq('authenticated') - end - end - - it "doesn't log the user in otherwise" do - expect(authentication_metrics) - .to increment(:user_unauthenticated_counter) - - get :index, private_token: "token" - - expect(response.status).not_to eq(200) - expect(response.body).not_to eq('authenticated') - end - end - describe 'session expiration' do controller(described_class) do # The anonymous controller will report 401 and fail to run any actions. @@ -167,7 +114,7 @@ describe ApplicationController do skip_before_action :authenticate_user!, only: :index def index - render text: 'authenticated' + render html: 'authenticated' end end @@ -224,74 +171,6 @@ describe ApplicationController do end end - describe '#authenticate_sessionless_user!' do - before do - stub_authentication_activity_metrics(debug: false) - end - - describe 'authenticating a user from a feed token' do - controller(described_class) do - def index - render text: 'authenticated' - end - end - - context "when the 'feed_token' param is populated with the feed token" do - context 'when the request format is atom' do - it "logs the user in" do - expect(authentication_metrics) - .to increment(:user_authenticated_counter) - .and increment(:user_session_override_counter) - .and increment(:user_sessionless_authentication_counter) - - get :index, feed_token: user.feed_token, format: :atom - - expect(response).to have_gitlab_http_status 200 - expect(response.body).to eq 'authenticated' - end - end - - context 'when the request format is ics' do - it "logs the user in" do - expect(authentication_metrics) - .to increment(:user_authenticated_counter) - .and increment(:user_session_override_counter) - .and increment(:user_sessionless_authentication_counter) - - get :index, feed_token: user.feed_token, format: :ics - - expect(response).to have_gitlab_http_status 200 - expect(response.body).to eq 'authenticated' - end - end - - context 'when the request format is neither atom nor ics' do - it "doesn't log the user in" do - expect(authentication_metrics) - .to increment(:user_unauthenticated_counter) - - get :index, feed_token: user.feed_token - - expect(response.status).not_to have_gitlab_http_status 200 - expect(response.body).not_to eq 'authenticated' - end - end - end - - context "when the 'feed_token' param is populated with an invalid feed token" do - it "doesn't log the user" do - expect(authentication_metrics) - .to increment(:user_unauthenticated_counter) - - get :index, feed_token: 'token', format: :atom - - expect(response.status).not_to eq 200 - expect(response.body).not_to eq 'authenticated' - end - end - end - end - describe '#route_not_found' do it 'renders 404 if authenticated' do allow(controller).to receive(:current_user).and_return(user) @@ -522,7 +401,7 @@ describe ApplicationController do context 'terms' do controller(described_class) do def index - render text: 'authenticated' + render html: 'authenticated' end end @@ -557,36 +436,6 @@ describe ApplicationController do expect(response).to have_gitlab_http_status(200) end - - context 'for sessionless users' do - render_views - - before do - sign_out user - end - - it 'renders a 403 when the sessionless user did not accept the terms' do - get :index, feed_token: user.feed_token, format: :atom - - expect(response).to have_gitlab_http_status(403) - end - - it 'renders the error message when the format was html' do - get :index, - private_token: create(:personal_access_token, user: user).token, - format: :html - - expect(response.body).to have_content /accept the terms of service/i - end - - it 'renders a 200 when the sessionless user accepted the terms' do - accept_terms(user) - - get :index, feed_token: user.feed_token, format: :atom - - expect(response).to have_gitlab_http_status(200) - end - end end end @@ -595,7 +444,7 @@ describe ApplicationController do attr_reader :last_payload def index - render text: 'authenticated' + render html: 'authenticated' end def append_info_to_payload(payload) @@ -611,6 +460,14 @@ describe ApplicationController do expect(controller.last_payload.has_key?(:response)).to be_falsey end + it 'does log correlation id' do + Gitlab::CorrelationId.use_id('new-id') do + get :index + end + + expect(controller.last_payload).to include('correlation_id' => 'new-id') + end + context '422 errors' do it 'logs a response with a string' do response = spy(ActionDispatch::Response, status: 422, body: 'Hello world', content_type: 'application/json', cookies: {}) diff --git a/spec/controllers/boards/issues_controller_spec.rb b/spec/controllers/boards/issues_controller_spec.rb index 98946e4287b..6d0483f0032 100644 --- a/spec/controllers/boards/issues_controller_spec.rb +++ b/spec/controllers/boards/issues_controller_spec.rb @@ -50,7 +50,7 @@ describe Boards::IssuesController do parsed_response = JSON.parse(response.body) - expect(response).to match_response_schema('issues') + expect(response).to match_response_schema('entities/issue_boards') expect(parsed_response['issues'].length).to eq 2 expect(development.issues.map(&:relative_position)).not_to include(nil) end @@ -121,7 +121,7 @@ describe Boards::IssuesController do parsed_response = JSON.parse(response.body) - expect(response).to match_response_schema('issues') + expect(response).to match_response_schema('entities/issue_boards') expect(parsed_response['issues'].length).to eq 2 end end @@ -168,7 +168,7 @@ describe Boards::IssuesController do it 'returns the created issue' do create_issue user: user, board: board, list: list1, title: 'New issue' - expect(response).to match_response_schema('issue') + expect(response).to match_response_schema('entities/issue_board') end end diff --git a/spec/controllers/concerns/issuable_collections_spec.rb b/spec/controllers/concerns/issuable_collections_spec.rb index e93c923fd39..f87eed6ff9f 100644 --- a/spec/controllers/concerns/issuable_collections_spec.rb +++ b/spec/controllers/concerns/issuable_collections_spec.rb @@ -86,6 +86,7 @@ describe IssuableCollections do it 'only allows whitelisted params' do allow(controller).to receive(:cookies).and_return({}) + allow(controller).to receive(:current_user).and_return(nil) finder_options = controller.send(:finder_options) diff --git a/spec/controllers/dashboard/projects_controller_spec.rb b/spec/controllers/dashboard/projects_controller_spec.rb new file mode 100644 index 00000000000..2975205e09c --- /dev/null +++ b/spec/controllers/dashboard/projects_controller_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe Dashboard::ProjectsController do + it_behaves_like 'authenticates sessionless user', :index, :atom +end diff --git a/spec/controllers/dashboard/todos_controller_spec.rb b/spec/controllers/dashboard/todos_controller_spec.rb index b4a731fd3a3..e2c799f5205 100644 --- a/spec/controllers/dashboard/todos_controller_spec.rb +++ b/spec/controllers/dashboard/todos_controller_spec.rb @@ -42,6 +42,16 @@ describe Dashboard::TodosController do end end + context 'group authorization' do + it 'renders 404 when user does not have read access on given group' do + unauthorized_group = create(:group, :private) + + get :index, group_id: unauthorized_group.id + + expect(response).to have_gitlab_http_status(404) + end + end + context 'when using pagination' do let(:last_page) { user.todos.page.total_pages } let!(:issues) { create_list(:issue, 3, project: project, assignees: [user]) } diff --git a/spec/controllers/dashboard_controller_spec.rb b/spec/controllers/dashboard_controller_spec.rb index 187542ba30c..c857a78d5e8 100644 --- a/spec/controllers/dashboard_controller_spec.rb +++ b/spec/controllers/dashboard_controller_spec.rb @@ -1,21 +1,26 @@ require 'spec_helper' describe DashboardController do - let(:user) { create(:user) } - let(:project) { create(:project) } + context 'signed in' do + let(:user) { create(:user) } + let(:project) { create(:project) } - before do - project.add_maintainer(user) - sign_in(user) - end + before do + project.add_maintainer(user) + sign_in(user) + end - describe 'GET issues' do - it_behaves_like 'issuables list meta-data', :issue, :issues - it_behaves_like 'issuables requiring filter', :issues - end + describe 'GET issues' do + it_behaves_like 'issuables list meta-data', :issue, :issues + it_behaves_like 'issuables requiring filter', :issues + end - describe 'GET merge requests' do - it_behaves_like 'issuables list meta-data', :merge_request, :merge_requests - it_behaves_like 'issuables requiring filter', :merge_requests + describe 'GET merge requests' do + it_behaves_like 'issuables list meta-data', :merge_request, :merge_requests + it_behaves_like 'issuables requiring filter', :merge_requests + end end + + it_behaves_like 'authenticates sessionless user', :issues, :atom, author_id: User.first + it_behaves_like 'authenticates sessionless user', :issues_calendar, :ics end diff --git a/spec/controllers/graphql_controller_spec.rb b/spec/controllers/graphql_controller_spec.rb index 1449036e148..949ad532365 100644 --- a/spec/controllers/graphql_controller_spec.rb +++ b/spec/controllers/graphql_controller_spec.rb @@ -52,15 +52,58 @@ describe GraphqlController do end end + context 'token authentication' do + before do + stub_authentication_activity_metrics(debug: false) + end + + let(:user) { create(:user, username: 'Simon') } + let(:personal_access_token) { create(:personal_access_token, user: user) } + + context "when the 'personal_access_token' param is populated with the personal access token" do + it 'logs the user in' do + expect(authentication_metrics) + .to increment(:user_authenticated_counter) + .and increment(:user_session_override_counter) + .and increment(:user_sessionless_authentication_counter) + + run_test_query!(private_token: personal_access_token.token) + + expect(response).to have_gitlab_http_status(200) + expect(query_response).to eq('echo' => '"Simon" says: test success') + end + end + + context 'when the personal access token has no api scope' do + it 'does not log the user in' do + personal_access_token.update(scopes: [:read_user]) + + run_test_query!(private_token: personal_access_token.token) + + expect(response).to have_gitlab_http_status(200) + + expect(query_response).to eq('echo' => 'nil says: test success') + end + end + + context 'without token' do + it 'shows public data' do + run_test_query! + + expect(query_response).to eq('echo' => 'nil says: test success') + end + end + end + # Chosen to exercise all the moving parts in GraphqlController#execute - def run_test_query!(variables: { 'text' => 'test success' }) + def run_test_query!(variables: { 'text' => 'test success' }, private_token: nil) query = <<~QUERY query Echo($text: String) { echo(text: $text) } QUERY - post :execute, query: query, operationName: 'Echo', variables: variables + post :execute, query: query, operationName: 'Echo', variables: variables, private_token: private_token end def query_response diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb index 4de61b65f71..4b0dc4c9b69 100644 --- a/spec/controllers/groups_controller_spec.rb +++ b/spec/controllers/groups_controller_spec.rb @@ -226,9 +226,10 @@ describe GroupsController do end context 'searching' do - # Remove as part of https://gitlab.com/gitlab-org/gitlab-ce/issues/52271 before do + # Remove in https://gitlab.com/gitlab-org/gitlab-ce/issues/54643 stub_feature_flags(use_cte_for_group_issues_search: false) + stub_feature_flags(use_subquery_for_group_issues_search: true) end it 'works with popularity sort' do @@ -606,4 +607,24 @@ describe GroupsController do end end end + + context 'token authentication' do + it_behaves_like 'authenticates sessionless user', :show, :atom, public: true do + before do + default_params.merge!(id: group) + end + end + + it_behaves_like 'authenticates sessionless user', :issues, :atom, public: true do + before do + default_params.merge!(id: group, author_id: user.id) + end + end + + it_behaves_like 'authenticates sessionless user', :issues_calendar, :ics, public: true do + before do + default_params.merge!(id: group) + end + end + end end diff --git a/spec/controllers/import/bitbucket_server_controller_spec.rb b/spec/controllers/import/bitbucket_server_controller_spec.rb index 77060fdc3be..db912641894 100644 --- a/spec/controllers/import/bitbucket_server_controller_spec.rb +++ b/spec/controllers/import/bitbucket_server_controller_spec.rb @@ -126,7 +126,7 @@ describe Import::BitbucketServerController do end it 'assigns repository categories' do - created_project = create(:project, import_type: 'bitbucket_server', creator_id: user.id, import_status: 'finished', import_source: @created_repo.browse_url) + created_project = create(:project, :import_finished, import_type: 'bitbucket_server', creator_id: user.id, import_source: @created_repo.browse_url) repos = instance_double(BitbucketServer::Collection) expect(repos).to receive(:partition).and_return([[@repo, @created_repo], [@invalid_repo]]) diff --git a/spec/controllers/oauth/applications_controller_spec.rb b/spec/controllers/oauth/applications_controller_spec.rb index ace8a954e92..b4219856fc0 100644 --- a/spec/controllers/oauth/applications_controller_spec.rb +++ b/spec/controllers/oauth/applications_controller_spec.rb @@ -40,6 +40,23 @@ describe Oauth::ApplicationsController do expect(response).to have_gitlab_http_status(302) expect(response).to redirect_to(profile_path) end + + context 'redirect_uri' do + render_views + + it 'shows an error for a forbidden URI' do + invalid_uri_params = { + doorkeeper_application: { + name: 'foo', + redirect_uri: 'javascript://alert()' + } + } + + post :create, invalid_uri_params + + expect(response.body).to include 'Redirect URI is forbidden by the server' + end + end end end 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 3c5a21c47fa..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 diff --git a/spec/controllers/projects/commits_controller_spec.rb b/spec/controllers/projects/commits_controller_spec.rb index a43bdd3ea80..5c72dab698c 100644 --- a/spec/controllers/projects/commits_controller_spec.rb +++ b/spec/controllers/projects/commits_controller_spec.rb @@ -5,87 +5,115 @@ 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 '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' } + context "valid branch, valid file" do + let(:id) { 'master/README.md' } - it { is_expected.to respond_with(:success) } - end + it { is_expected.to respond_with(:success) } + end - context "valid branch, invalid file" do - let(:id) { 'master/invalid-path.rb' } + context "valid branch, invalid file" do + let(:id) { 'master/invalid-path.rb' } - it { is_expected.to respond_with(:not_found) } - end + it { is_expected.to respond_with(:not_found) } + end - context "invalid branch, valid file" do - let(:id) { 'invalid-branch/README.md' } + context "invalid branch, valid file" do + let(:id) { 'invalid-branch/README.md' } - it { is_expected.to respond_with(:not_found) } + 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 - before do - get(:show, - namespace_id: project.namespace, - project_id: project, - id: "master.atom") + 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 - it "renders as atom" do - expect(response).to be_success - expect(response.content_type).to eq('application/atom+xml') - end + context "when the ref exists with the suffix" do + before do + commit = project.repository.commit('master') - it 'renders summary with type=html' do - expect(response.body).to include('<summary type="html">') + 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 + end - context "when the ref exists 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 - commit = project.repository.commit('master') + public_project = create(:project, :repository, :public) - 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") + default_params.merge!(namespace_id: public_project.namespace, project_id: public_project, id: "master.atom") end + end + end + + context 'private project' do + it_behaves_like 'authenticates sessionless user', :show, :atom, public: false do + before do + 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/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 bd193979192..fca313dafb1 100644 --- a/spec/controllers/projects/jobs_controller_spec.rb +++ b/spec/controllers/projects/jobs_controller_spec.rb @@ -876,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 @@ -904,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/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 diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index 3bc9cbe64c5..7849bec4762 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -882,6 +882,28 @@ describe ProjectsController do end end + context 'private project with token authentication' do + let(:private_project) { create(:project, :private) } + + it_behaves_like 'authenticates sessionless user', :show, :atom do + before do + default_params.merge!(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', :show, :atom, public: true do + before do + default_params.merge!(id: public_project, namespace_id: public_project.namespace) + end + end + end + def project_moved_message(redirect_route, project) "Project '#{redirect_route.path}' was moved to '#{project.full_path}'. Please update any links and bookmarks that may still have the old path." end diff --git a/spec/controllers/snippets_controller_spec.rb b/spec/controllers/snippets_controller_spec.rb index 9effe47ab05..957bab638b1 100644 --- a/spec/controllers/snippets_controller_spec.rb +++ b/spec/controllers/snippets_controller_spec.rb @@ -437,7 +437,10 @@ describe SnippetsController do end context 'when signed in user is the author' do + let(:flag_value) { false } + before do + stub_feature_flags(workhorse_set_content_type: flag_value) get :raw, id: personal_snippet.to_param end @@ -451,6 +454,24 @@ describe SnippetsController do expect(response.header['Content-Disposition']).to match(/inline/) end + + context 'when feature flag workhorse_set_content_type is' do + context 'enabled' do + let(:flag_value) { true } + + it "sets #{Gitlab::Workhorse::DETECT_HEADER} header" do + expect(response).to have_gitlab_http_status(200) + expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true" + end + end + + context 'disabled' do + it "does not set #{Gitlab::Workhorse::DETECT_HEADER} header" do + expect(response).to have_gitlab_http_status(200) + expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to be nil + end + end + end end end diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 071f96a729e..fe438e71e9e 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -395,6 +395,14 @@ describe UsersController do end end + context 'token authentication' do + it_behaves_like 'authenticates sessionless user', :show, :atom, public: true do + before do + default_params.merge!(username: user.username) + end + end + end + def user_moved_message(redirect_route, user) "User '#{redirect_route.path}' was moved to '#{user.full_path}'. Please update any links and bookmarks that may still have the old path." end |