diff options
Diffstat (limited to 'spec/controllers')
13 files changed, 721 insertions, 46 deletions
diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb index aadd3317875..25fe547ff37 100644 --- a/spec/controllers/admin/users_controller_spec.rb +++ b/spec/controllers/admin/users_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Admin::UsersController do let(:user) { create(:user) } - let(:admin) { create(:admin) } + set(:admin) { create(:admin) } before do sign_in(admin) diff --git a/spec/controllers/dashboard/todos_controller_spec.rb b/spec/controllers/dashboard/todos_controller_spec.rb index c8c6b9f41bf..9df4ebf2fa0 100644 --- a/spec/controllers/dashboard/todos_controller_spec.rb +++ b/spec/controllers/dashboard/todos_controller_spec.rb @@ -57,7 +57,7 @@ describe Dashboard::TodosController do expect(response).to redirect_to(dashboard_todos_path(page: last_page)) end - it 'redirects to correspondent page' do + it 'goes to the correct page' do get :index, page: last_page expect(assigns(:todos).current_page).to eq(last_page) @@ -70,6 +70,30 @@ describe Dashboard::TodosController do expect(response).to redirect_to(dashboard_todos_path(page: last_page)) end + + context 'when providing no filters' do + it 'does not perform a query to get the page count, but gets that from the user' do + allow(controller).to receive(:current_user).and_return(user) + + expect(user).to receive(:todos_pending_count).and_call_original + + get :index, page: (last_page + 1).to_param, sort: :created_asc + + expect(response).to redirect_to(dashboard_todos_path(page: last_page, sort: :created_asc)) + end + end + + context 'when providing filters' do + it 'performs a query to get the correct page count' do + allow(controller).to receive(:current_user).and_return(user) + + expect(user).not_to receive(:todos_pending_count) + + get :index, page: (last_page + 1).to_param, project_id: project.id + + expect(response).to redirect_to(dashboard_todos_path(page: last_page, project_id: project.id)) + end + end end end diff --git a/spec/controllers/google_api/authorizations_controller_spec.rb b/spec/controllers/google_api/authorizations_controller_spec.rb new file mode 100644 index 00000000000..80d553f0f34 --- /dev/null +++ b/spec/controllers/google_api/authorizations_controller_spec.rb @@ -0,0 +1,49 @@ +require 'spec_helper' + +describe GoogleApi::AuthorizationsController do + describe 'GET|POST #callback' do + let(:user) { create(:user) } + let(:token) { 'token' } + let(:expires_at) { 1.hour.since.strftime('%s') } + + subject { get :callback, code: 'xxx', state: @state } + + before do + sign_in(user) + + allow_any_instance_of(GoogleApi::CloudPlatform::Client) + .to receive(:get_token).and_return([token, expires_at]) + end + + it 'sets token and expires_at in session' do + subject + + expect(session[GoogleApi::CloudPlatform::Client.session_key_for_token]) + .to eq(token) + expect(session[GoogleApi::CloudPlatform::Client.session_key_for_expires_at]) + .to eq(expires_at) + end + + context 'when redirect uri key is stored in state' do + set(:project) { create(:project) } + let(:redirect_uri) { project_clusters_url(project).to_s } + + before do + @state = GoogleApi::CloudPlatform::Client + .new_session_key_for_redirect_uri do |key| + session[key] = redirect_uri + end + end + + it 'redirects to the URL stored in state param' do + expect(subject).to redirect_to(redirect_uri) + end + end + + context 'when redirection url is not stored in state' do + it 'redirects to root_path' do + expect(subject).to redirect_to(root_path) + end + end + end +end diff --git a/spec/controllers/profiles/emails_controller_spec.rb b/spec/controllers/profiles/emails_controller_spec.rb new file mode 100644 index 00000000000..ecf14aad54f --- /dev/null +++ b/spec/controllers/profiles/emails_controller_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +describe Profiles::EmailsController do + let(:user) { create(:user) } + + before do + sign_in(user) + end + + describe '#create' do + let(:email_params) { { email: "add_email@example.com" } } + + it 'sends an email confirmation' do + expect { post(:create, { email: email_params }) }.to change { ActionMailer::Base.deliveries.size } + expect(ActionMailer::Base.deliveries.last.to).to eq [email_params[:email]] + expect(ActionMailer::Base.deliveries.last.subject).to match "Confirmation instructions" + end + end + + describe '#resend_confirmation_instructions' do + let(:email_params) { { email: "add_email@example.com" } } + + it 'resends an email confirmation' do + email = user.emails.create(email: 'add_email@example.com') + + expect { put(:resend_confirmation_instructions, { id: email }) }.to change { ActionMailer::Base.deliveries.size } + expect(ActionMailer::Base.deliveries.last.to).to eq [email_params[:email]] + expect(ActionMailer::Base.deliveries.last.subject).to match "Confirmation instructions" + end + + it 'unable to resend an email confirmation' do + expect { put(:resend_confirmation_instructions, { id: 1 }) }.not_to change { ActionMailer::Base.deliveries.size } + end + end +end diff --git a/spec/controllers/profiles_controller_spec.rb b/spec/controllers/profiles_controller_spec.rb index b52b63e05a4..ce5040ff02b 100644 --- a/spec/controllers/profiles_controller_spec.rb +++ b/spec/controllers/profiles_controller_spec.rb @@ -15,6 +15,20 @@ describe ProfilesController do expect(user.unconfirmed_email).to eq('john@gmail.com') end + it "allows an email update without confirmation if existing verified email" do + user = create(:user) + create(:email, :confirmed, user: user, email: 'john@gmail.com') + sign_in(user) + + put :update, + user: { email: "john@gmail.com", name: "John" } + + user.reload + + expect(response.status).to eq(302) + expect(user.unconfirmed_email).to eq nil + end + it "ignores an email update from a user with an external email address" do stub_omniauth_setting(sync_profile_from_provider: ['ldap']) stub_omniauth_setting(sync_profile_attributes: true) diff --git a/spec/controllers/projects/artifacts_controller_spec.rb b/spec/controllers/projects/artifacts_controller_spec.rb index caa63e7bd22..d0992719171 100644 --- a/spec/controllers/projects/artifacts_controller_spec.rb +++ b/spec/controllers/projects/artifacts_controller_spec.rb @@ -1,8 +1,8 @@ require 'spec_helper' describe Projects::ArtifactsController do - let(:user) { create(:user) } - let(:project) { create(:project, :repository) } + set(:user) { create(:user) } + set(:project) { create(:project, :repository, :public) } let(:pipeline) do create(:ci_pipeline, @@ -15,7 +15,7 @@ describe Projects::ArtifactsController do let(:job) { create(:ci_build, :success, :artifacts, pipeline: pipeline) } before do - project.team << [user, :developer] + project.add_developer(user) sign_in(user) end @@ -47,19 +47,67 @@ describe Projects::ArtifactsController do end describe 'GET file' do - context 'when the file exists' do - it 'renders the file view' do - get :file, namespace_id: project.namespace, project_id: project, job_id: job, path: 'ci_artifacts.txt' + before do + allow(Gitlab.config.pages).to receive(:enabled).and_return(true) + end - expect(response).to render_template('projects/artifacts/file') + context 'when the file is served by GitLab Pages' do + before do + allow(Gitlab.config.pages).to receive(:artifacts_server).and_return(true) + end + + context 'when the file exists' do + it 'renders the file view' do + get :file, namespace_id: project.namespace, project_id: project, job_id: job, path: 'ci_artifacts.txt' + + expect(response).to have_http_status(302) + end + end + + context 'when the file does not exist' do + it 'responds Not Found' do + get :file, namespace_id: project.namespace, project_id: project, job_id: job, path: 'unknown' + + expect(response).to be_not_found + end end end - context 'when the file does not exist' do - it 'responds Not Found' do - get :file, namespace_id: project.namespace, project_id: project, job_id: job, path: 'unknown' + context 'when the file is served through Rails' do + context 'when the file exists' do + it 'renders the file view' do + get :file, namespace_id: project.namespace, project_id: project, job_id: job, path: 'ci_artifacts.txt' - expect(response).to be_not_found + expect(response).to have_http_status(:ok) + expect(response).to render_template('projects/artifacts/file') + end + end + + context 'when the file does not exist' do + it 'responds Not Found' do + get :file, namespace_id: project.namespace, project_id: project, job_id: job, path: 'unknown' + + expect(response).to be_not_found + end + end + end + + context 'when the project is private' do + let(:private_project) { create(:project, :repository, :private) } + let(:pipeline) { create(:ci_pipeline, project: private_project) } + let(:job) { create(:ci_build, :success, :artifacts, pipeline: pipeline) } + + before do + private_project.add_developer(user) + + allow(Gitlab.config.pages).to receive(:artifacts_server).and_return(true) + end + + it 'does not redirect the request' do + get :file, namespace_id: private_project.namespace, project_id: private_project, job_id: job, path: 'ci_artifacts.txt' + + expect(response).to have_http_status(:ok) + expect(response).to render_template('projects/artifacts/file') end end end diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb new file mode 100644 index 00000000000..7985028d73b --- /dev/null +++ b/spec/controllers/projects/clusters_controller_spec.rb @@ -0,0 +1,308 @@ +require 'spec_helper' + +describe Projects::ClustersController do + set(:user) { create(:user) } + set(:project) { create(:project) } + let(:role) { :master } + + before do + project.team << [user, role] + + sign_in(user) + end + + describe 'GET index' do + subject do + get :index, namespace_id: project.namespace, + project_id: project + end + + context 'when cluster is already created' do + let!(:cluster) { create(:gcp_cluster, :created_on_gke, project: project) } + + it 'redirects to show a cluster' do + subject + + expect(response).to redirect_to(project_cluster_path(project, cluster)) + end + end + + context 'when we do not have cluster' do + it 'redirects to create a cluster' do + subject + + expect(response).to redirect_to(new_project_cluster_path(project)) + end + end + end + + describe 'GET login' do + render_views + + subject do + get :login, namespace_id: project.namespace, + project_id: project + end + + context 'when we do have omniauth configured' do + it 'shows login button' do + subject + + expect(response.body).to include('auth_buttons/signin_with_google') + end + end + + context 'when we do not have omniauth configured' do + before do + stub_omniauth_setting(providers: []) + end + + it 'shows notice message' do + subject + + expect(response.body).to include('Ask your GitLab administrator if you want to use this service.') + end + end + end + + shared_examples 'requires to login' do + it 'redirects to create a cluster' do + subject + + expect(response).to redirect_to(login_project_clusters_path(project)) + end + end + + describe 'GET new' do + render_views + + subject do + get :new, namespace_id: project.namespace, + project_id: project + end + + context 'when logged' do + before do + make_logged_in + end + + it 'shows a creation form' do + subject + + expect(response.body).to include('Create cluster') + end + end + + context 'when not logged' do + it_behaves_like 'requires to login' + end + end + + describe 'POST create' do + subject do + post :create, params.merge(namespace_id: project.namespace, + project_id: project) + end + + context 'when not logged' do + let(:params) { {} } + + it_behaves_like 'requires to login' + end + + context 'when logged in' do + before do + make_logged_in + end + + context 'when all required parameters are set' do + let(:params) do + { + cluster: { + gcp_cluster_name: 'new-cluster', + gcp_project_id: '111' + } + } + end + + before do + expect(ClusterProvisionWorker).to receive(:perform_async) { } + end + + it 'creates a new cluster' do + expect { subject }.to change { Gcp::Cluster.count } + + expect(response).to redirect_to(project_cluster_path(project, project.cluster)) + end + end + + context 'when not all required parameters are set' do + render_views + + let(:params) do + { + cluster: { + project_namespace: 'some namespace' + } + } + end + + it 'shows an error message' do + expect { subject }.not_to change { Gcp::Cluster.count } + + expect(response).to render_template(:new) + end + end + end + end + + describe 'GET status' do + let(:cluster) { create(:gcp_cluster, :created_on_gke, project: project) } + + subject do + get :status, namespace_id: project.namespace, + project_id: project, + id: cluster, + format: :json + end + + it "responds with matching schema" do + subject + + expect(response).to have_http_status(:ok) + expect(response).to match_response_schema('cluster_status') + end + end + + describe 'GET show' do + render_views + + let(:cluster) { create(:gcp_cluster, :created_on_gke, project: project) } + + subject do + get :show, namespace_id: project.namespace, + project_id: project, + id: cluster + end + + context 'when logged as master' do + it "allows to update cluster" do + subject + + expect(response).to have_http_status(:ok) + expect(response.body).to include("Save") + end + + it "allows remove integration" do + subject + + expect(response).to have_http_status(:ok) + expect(response.body).to include("Remove integration") + end + end + + context 'when logged as developer' do + let(:role) { :developer } + + it "does not allow to access page" do + subject + + expect(response).to have_http_status(:not_found) + end + end + end + + describe 'PUT update' do + render_views + + let(:service) { project.build_kubernetes_service } + let(:cluster) { create(:gcp_cluster, :created_on_gke, project: project, service: service) } + let(:params) { {} } + + subject do + put :update, params.merge(namespace_id: project.namespace, + project_id: project, + id: cluster) + end + + context 'when logged as master' do + context 'when valid params are used' do + let(:params) do + { + cluster: { enabled: false } + } + end + + it "redirects back to show page" do + subject + + expect(response).to redirect_to(project_cluster_path(project, project.cluster)) + expect(flash[:notice]).to eq('Cluster was successfully updated.') + end + end + + context 'when invalid params are used' do + let(:params) do + { + cluster: { project_namespace: 'my Namespace 321321321 #' } + } + end + + it "rejects changes" do + subject + + expect(response).to have_http_status(:ok) + expect(response).to render_template(:show) + end + end + end + + context 'when logged as developer' do + let(:role) { :developer } + + it "does not allow to update cluster" do + subject + + expect(response).to have_http_status(:not_found) + end + end + end + + describe 'delete update' do + let(:cluster) { create(:gcp_cluster, :created_on_gke, project: project) } + + subject do + delete :destroy, namespace_id: project.namespace, + project_id: project, + id: cluster + end + + context 'when logged as master' do + it "redirects back to clusters list" do + subject + + expect(response).to redirect_to(project_clusters_path(project)) + expect(flash[:notice]).to eq('Cluster integration was successfully removed.') + end + end + + context 'when logged as developer' do + let(:role) { :developer } + + it "does not allow to destroy cluster" do + subject + + expect(response).to have_http_status(:not_found) + end + end + end + + def make_logged_in + session[GoogleApi::CloudPlatform::Client.session_key_for_token] = '1234' + session[GoogleApi::CloudPlatform::Client.session_key_for_expires_at] = in_hour.to_i.to_s + end + + def in_hour + Time.now + 1.hour + end +end diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 629c131aee6..e46d1995498 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -96,18 +96,6 @@ describe Projects::MergeRequestsController do expect(response).to match_response_schema('entities/merge_request') end end - - context 'number of queries', :request_store do - it 'verifies number of queries' do - # pre-create objects - merge_request - - recorded = ActiveRecord::QueryRecorder.new { go(format: :json) } - - expect(recorded.count).to be_within(5).of(30) - expect(recorded.cached_count).to eq(0) - end - end end describe "as diff" do diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb index c0337f96fc6..e3114e5c06e 100644 --- a/spec/controllers/projects/notes_controller_spec.rb +++ b/spec/controllers/projects/notes_controller_spec.rb @@ -266,6 +266,56 @@ describe Projects::NotesController do end end end + + context 'when the merge request discussion is locked' do + before do + project.update_attribute(:visibility_level, Gitlab::VisibilityLevel::PUBLIC) + merge_request.update_attribute(:discussion_locked, true) + end + + context 'when a noteable is not found' do + it 'returns 404 status' do + request_params[:note][:noteable_id] = 9999 + post :create, request_params.merge(format: :json) + + expect(response).to have_http_status(404) + end + end + + context 'when a user is a team member' do + it 'returns 302 status for html' do + post :create, request_params + + expect(response).to have_http_status(302) + end + + it 'returns 200 status for json' do + post :create, request_params.merge(format: :json) + + expect(response).to have_http_status(200) + end + + it 'creates a new note' do + expect { post :create, request_params }.to change { Note.count }.by(1) + end + end + + context 'when a user is not a team member' do + before do + project.project_member(user).destroy + end + + it 'returns 404 status' do + post :create, request_params + + expect(response).to have_http_status(404) + end + + it 'does not create a new note' do + expect { post :create, request_params }.not_to change { Note.count } + end + end + end end describe 'DELETE destroy' do diff --git a/spec/controllers/projects/registry/repositories_controller_spec.rb b/spec/controllers/projects/registry/repositories_controller_spec.rb index 2805968dcd9..5d9d5351687 100644 --- a/spec/controllers/projects/registry/repositories_controller_spec.rb +++ b/spec/controllers/projects/registry/repositories_controller_spec.rb @@ -42,6 +42,13 @@ describe Projects::Registry::RepositoriesController do expect { go_to_index }.to change { ContainerRepository.all.count }.by(1) expect(ContainerRepository.first).to be_root_repository end + + it 'json has a list of projects' do + go_to_index(format: :json) + + expect(response).to have_http_status(:ok) + expect(response).to match_response_schema('registry/repositories') + end end context 'when there are no tags for this repository' do @@ -58,6 +65,31 @@ describe Projects::Registry::RepositoriesController do it 'does not ensure root container repository' do expect { go_to_index }.not_to change { ContainerRepository.all.count } end + + it 'responds with json if asked' do + go_to_index(format: :json) + + expect(response).to have_http_status(:ok) + expect(json_response).to be_kind_of(Array) + end + end + end + end + + describe 'DELETE destroy' do + context 'when root container repository exists' do + let!(:repository) do + create(:container_repository, :root, project: project) + end + + before do + stub_container_registry_tags(repository: :any, tags: []) + end + + it 'deletes a repository' do + expect { delete_repository(repository) }.to change { ContainerRepository.all.count }.by(-1) + + expect(response).to have_http_status(:no_content) end end end @@ -77,8 +109,16 @@ describe Projects::Registry::RepositoriesController do end end - def go_to_index + def go_to_index(format: :html) get :index, namespace_id: project.namespace, - project_id: project + project_id: project, + format: format + end + + def delete_repository(repository) + delete :destroy, namespace_id: project.namespace, + project_id: project, + id: repository, + format: :json end end diff --git a/spec/controllers/projects/registry/tags_controller_spec.rb b/spec/controllers/projects/registry/tags_controller_spec.rb index f4af3587d23..bb702ebeb23 100644 --- a/spec/controllers/projects/registry/tags_controller_spec.rb +++ b/spec/controllers/projects/registry/tags_controller_spec.rb @@ -4,24 +4,83 @@ describe Projects::Registry::TagsController do let(:user) { create(:user) } let(:project) { create(:project, :private) } + let(:repository) do + create(:container_repository, name: 'image', project: project) + end + before do sign_in(user) stub_container_registry_config(enabled: true) end - context 'when user has access to registry' do + describe 'GET index' do + let(:tags) do + Array.new(40) { |i| "tag#{i}" } + end + before do - project.add_developer(user) + stub_container_registry_tags(repository: /image/, tags: tags) end - describe 'POST destroy' do + context 'when user can control the registry' do + before do + project.add_developer(user) + end + + it 'receive a list of tags' do + get_tags + + expect(response).to have_http_status(:ok) + expect(response).to match_response_schema('registry/tags') + expect(response).to include_pagination_headers + end + end + + context 'when user can read the registry' do + before do + project.add_reporter(user) + end + + it 'receive a list of tags' do + get_tags + + expect(response).to have_http_status(:ok) + expect(response).to match_response_schema('registry/tags') + expect(response).to include_pagination_headers + end + end + + context 'when user does not have access to registry' do + before do + project.add_guest(user) + end + + it 'does not receive a list of tags' do + get_tags + + expect(response).to have_http_status(:not_found) + end + end + + private + + def get_tags + get :index, namespace_id: project.namespace, + project_id: project, + repository_id: repository, + format: :json + end + end + + describe 'POST destroy' do + context 'when user has access to registry' do + before do + project.add_developer(user) + end + context 'when there is matching tag present' do before do - stub_container_registry_tags(repository: /image/, tags: %w[rc1 test.]) - end - - let(:repository) do - create(:container_repository, name: 'image', project: project) + stub_container_registry_tags(repository: repository.path, tags: %w[rc1 test.]) end it 'makes it possible to delete regular tag' do @@ -37,12 +96,15 @@ describe Projects::Registry::TagsController do end end end - end - def destroy_tag(name) - post :destroy, namespace_id: project.namespace, - project_id: project, - repository_id: repository, - id: name + private + + def destroy_tag(name) + post :destroy, namespace_id: project.namespace, + project_id: project, + repository_id: repository, + id: name, + format: :json + end end end diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index 2a91a6613e6..491f35d0fb6 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -140,7 +140,8 @@ describe ProjectsController do end context 'when the storage is not available', broken_storage: true do - let(:project) { create(:project, :broken_storage) } + set(:project) { create(:project, :broken_storage) } + before do project.add_developer(user) sign_in(user) diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb index 5a4ab39ab86..1d3ddfbd220 100644 --- a/spec/controllers/registrations_controller_spec.rb +++ b/spec/controllers/registrations_controller_spec.rb @@ -76,12 +76,68 @@ describe RegistrationsController do sign_in(user) end - it 'schedules the user for destruction' do - expect(DeleteUserWorker).to receive(:perform_async).with(user.id, user.id, {}) + def expect_failure(message) + expect(flash[:alert]).to eq(message) + expect(response.status).to eq(303) + expect(response).to redirect_to profile_account_path + end + + def expect_password_failure + expect_failure('Invalid password') + end + + def expect_username_failure + expect_failure('Invalid username') + end + + def expect_success + expect(flash[:notice]).to eq 'Account scheduled for removal.' + expect(response.status).to eq(303) + expect(response).to redirect_to new_user_session_path + end - post(:destroy) + context 'user requires password confirmation' do + it 'fails if password confirmation is not provided' do + post :destroy - expect(response.status).to eq(302) + expect_password_failure + end + + it 'fails if password confirmation is wrong' do + post :destroy, password: 'wrong password' + + expect_password_failure + end + + it 'succeeds if password is confirmed' do + post :destroy, password: '12345678' + + expect_success + end + end + + context 'user does not require password confirmation' do + before do + stub_application_setting(password_authentication_enabled: false) + end + + it 'fails if username confirmation is not provided' do + post :destroy + + expect_username_failure + end + + it 'fails if username confirmation is wrong' do + post :destroy, username: 'wrong username' + + expect_username_failure + end + + it 'succeeds if username is confirmed' do + post :destroy, username: user.username + + expect_success + end end end end |