Commit 759bab05 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 61f0c589
......@@ -23,7 +23,7 @@
.signup-heading h2 {
font-weight: $gl-font-weight-bold;
padding: 0 10px;
padding: 0 $gl-padding;
@include media-breakpoint-down(md) {
font-size: $gl-font-size-large;
......
......@@ -17,7 +17,7 @@ class ApplicationController < ActionController::Base
include Gitlab::Tracking::ControllerConcern
include Gitlab::Experimentation::ControllerConcern
before_action :authenticate_user!
before_action :authenticate_user!, except: [:route_not_found]
before_action :enforce_terms!, if: :should_enforce_terms?
before_action :validate_user_service_ticket!
before_action :check_password_expiration
......@@ -30,7 +30,7 @@ class ApplicationController < ActionController::Base
before_action :active_user_check, unless: :devise_controller?
before_action :set_usage_stats_consent_flag
before_action :check_impersonation_availability
before_action :require_role
before_action :required_signup_info
around_action :set_locale
around_action :set_session_storage
......@@ -95,11 +95,13 @@ class ApplicationController < ActionController::Base
end
def route_not_found
# We need to call #authenticate_user! here because sometimes this is called from another action
# and not from our wildcard fallback route
authenticate_user!
if current_user
not_found
else
store_location_for(:user, request.fullpath) unless request.xhr?
not_found
redirect_to new_user_session_path, alert: I18n.t('devise.failure.unauthenticated')
end
end
def render(*args)
......@@ -536,10 +538,13 @@ class ApplicationController < ActionController::Base
@current_user_mode ||= Gitlab::Auth::CurrentUserMode.new(current_user)
end
# A user requires a role when they are part of the experimental signup flow (executed by the Growth team). Users
# are redirected to the welcome page when their role is required and the experiment is enabled for the current user.
def require_role
return unless current_user && current_user.role_required? && experiment_enabled?(:signup_flow)
# A user requires a role and have the setup_for_company attribute set when they are part of the experimental signup
# flow (executed by the Growth team). Users are redirected to the welcome page when their role is required and the
# experiment is enabled for the current user.
def required_signup_info
return unless current_user
return unless current_user.role_required?
return unless experiment_enabled?(:signup_flow)
store_location_for :user, request.fullpath
......
......@@ -8,7 +8,7 @@ class RegistrationsController < Devise::RegistrationsController
layout :choose_layout
skip_before_action :require_role, only: [:welcome, :update_role]
skip_before_action :required_signup_info, only: [:welcome, :update_registration]
prepend_before_action :check_captcha, only: :create
before_action :whitelist_query_limiting, only: [:destroy]
before_action :ensure_terms_accepted,
......@@ -53,22 +53,22 @@ class RegistrationsController < Devise::RegistrationsController
def welcome
return redirect_to new_user_registration_path unless current_user
return redirect_to stored_location_or_dashboard_or_almost_there_path(current_user) if current_user.role.present?
return redirect_to stored_location_or_dashboard_or_almost_there_path(current_user) if current_user.role.present? && !current_user.setup_for_company.nil?
current_user.name = nil
current_user.name = nil if current_user.name == current_user.username
render layout: 'devise_experimental_separate_sign_up_flow'
end
def update_role
user_params = params.require(:user).permit(:name, :role)
result = ::Users::UpdateService.new(current_user, user_params.merge(user: current_user)).execute
def update_registration
user_params = params.require(:user).permit(:name, :role, :setup_for_company)
result = ::Users::SignupService.new(current_user, user_params).execute
if result[:status] == :success
track_experiment_event(:signup_flow, 'end') # We want this event to be tracked when the user is _in_ the experimental group
set_flash_message! :notice, :signed_up
redirect_to stored_location_or_dashboard_or_almost_there_path(current_user)
else
redirect_to users_sign_up_welcome_path, alert: result[:message]
render :welcome, layout: 'devise_experimental_separate_sign_up_flow'
end
end
......
......@@ -385,6 +385,9 @@ class IssuableFinder
end
def count_key(value)
# value may be an array if the finder used in `count_by_state` added an
# additional `group by`. Anyway we are sure that state will be always the
# last item because it's added as the last one to the query.
value = Array(value).last
klass.available_states.key(value)
end
......
......@@ -18,6 +18,11 @@ class LfsObject < ApplicationRecord
after_save :update_file_store, if: :saved_change_to_file?
def self.not_linked_to_project(project)
where('NOT EXISTS (?)',
project.lfs_objects_projects.select(1).where('lfs_objects_projects.lfs_object_id = lfs_objects.id'))
end
def update_file_store
# The file.object_store is set during `uploader.store!`
# which happens after object is inserted/updated
......
......@@ -240,6 +240,7 @@ class User < ApplicationRecord
delegate :time_display_relative, :time_display_relative=, to: :user_preference
delegate :time_format_in_24h, :time_format_in_24h=, to: :user_preference
delegate :show_whitespace_in_diffs, :show_whitespace_in_diffs=, to: :user_preference
delegate :setup_for_company, :setup_for_company=, to: :user_preference
accepts_nested_attributes_for :user_preference, update_only: true
......
......@@ -4,6 +4,9 @@
module Projects
module LfsPointers
class LfsLinkService < BaseService
TooManyOidsError = Class.new(StandardError)
MAX_OIDS = 100_000
BATCH_SIZE = 1000
# Accept an array of oids to link
......@@ -12,6 +15,10 @@ module Projects
def execute(oids)
return [] unless project&.lfs_enabled?
if oids.size > MAX_OIDS
raise TooManyOidsError, 'Too many LFS object ids to link, please push them manually'
end
# Search and link existing LFS Object
link_existing_lfs_objects(oids)
end
......@@ -20,22 +27,27 @@ module Projects
# rubocop: disable CodeReuse/ActiveRecord
def link_existing_lfs_objects(oids)
all_existing_objects = []
linked_existing_objects = []
iterations = 0
LfsObject.where(oid: oids).each_batch(of: BATCH_SIZE) do |existent_lfs_objects|
oids.each_slice(BATCH_SIZE) do |oids_batch|
# Load all existing LFS Objects immediately so we don't issue an extra
# query for the `.any?`
existent_lfs_objects = LfsObject.where(oid: oids_batch).load
next unless existent_lfs_objects.any?
rows = existent_lfs_objects
.not_linked_to_project(project)
.map { |existing_lfs_object| { project_id: project.id, lfs_object_id: existing_lfs_object.id } }
Gitlab::Database.bulk_insert(:lfs_objects_projects, rows)
iterations += 1
not_linked_lfs_objects = existent_lfs_objects.where.not(id: project.all_lfs_objects)
project.all_lfs_objects << not_linked_lfs_objects
all_existing_objects += existent_lfs_objects.pluck(:oid)
linked_existing_objects += existent_lfs_objects.map(&:oid)
end
log_lfs_link_results(all_existing_objects.count, iterations)
log_lfs_link_results(linked_existing_objects.count, iterations)
all_existing_objects
linked_existing_objects
end
# rubocop: enable CodeReuse/ActiveRecord
......
# frozen_string_literal: true
module Users
class SignupService < BaseService
def initialize(current_user, params = {})
@user = current_user
@params = params.dup
end
def execute
assign_attributes
inject_validators
if @user.save
success
else
error(@user.errors.full_messages.join('. '))
end
end
private
def assign_attributes
@user.assign_attributes(params) unless params.empty?
end
def inject_validators
class << @user
validates :role, presence: true
validates :setup_for_company, inclusion: { in: [true, false], message: :blank }
end
end
end
end
- content_for(:page_title, _('Welcome to GitLab %{username}!') % { username: current_user.username })
- content_for(:page_title, _('Welcome to GitLab @%{username}!') % { username: current_user.username })
- max_name_length = 128
.text-center.mb-3
= _('In order to tailor your experience with GitLab<br>we would like to know a bit more about you.').html_safe
= _('In order to tailor your experience with GitLab we<br>would like to know a bit more about you.').html_safe
.signup-box.p-3.mb-2
.signup-body
= form_for(current_user, url: users_sign_up_update_role_path, html: { class: 'new_new_user gl-show-field-errors', 'aria-live' => 'assertive' }) do |f|
= form_for(current_user, url: users_sign_up_update_registration_path, html: { class: 'new_new_user gl-show-field-errors', 'aria-live' => 'assertive' }) do |f|
.devise-errors.mt-0
= render 'devise/shared/error_messages', resource: current_user
.name.form-group
......@@ -13,5 +13,14 @@
.form-group
= f.label :role, _('Role'), class: 'label-bold'
= f.select :role, ::User.roles.keys.map { |role| [role.titleize, role] }, {}, class: 'form-control'
.form-group
= f.label :setup_for_company, _('Are you setting up GitLab for a company?'), class: 'label-bold'
.d-flex.justify-content-center
.w-25
= f.radio_button :setup_for_company, true
= f.label :setup_for_company, _('Yes'), value: 'true'
.w-25
= f.radio_button :setup_for_company, false
= f.label :setup_for_company, _('No'), value: 'false'
.submit-container.mt-3
= f.submit _('Get started!'), class: 'btn-register btn btn-block mb-0 p-2'
---
title: Fix JSON responses returning 302 instead of 401
merge_request: 19412
author:
type: fixed
---
title: Improve performance of linking LFS objects during import
merge_request: 19709
author:
type: performance
---
title: Ask if the user is setting up GitLab for a company during signup
merge_request: 17999
author:
type: changed
......@@ -57,7 +57,7 @@ Rails.application.routes.draw do
# Sign up
get 'users/sign_up/welcome' => 'registrations#welcome'
patch 'users/sign_up/update_role' => 'registrations#update_role'
patch 'users/sign_up/update_registration' => 'registrations#update_registration'
# Search
get 'search' => 'search#show'
......
......@@ -52,7 +52,7 @@ scope(path: '*namespace_id/:project_id',
# /info/refs?service=git-receive-pack, but nothing else.
#
git_http_handshake = lambda do |request|
::Constraints::ProjectUrlConstrainer.new.matches?(request) &&
::Constraints::ProjectUrlConstrainer.new.matches?(request, existence_check: false) &&
(request.query_string.blank? ||
request.query_string.match(/\Aservice=git-(upload|receive)-pack\z/))
end
......
......@@ -245,6 +245,12 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
post :validate_query, on: :collection
end
end
Gitlab.ee do
resources :alerts, constraints: { id: /\d+/ }, only: [:index, :create, :show, :update, :destroy] do
post :notify, on: :collection
end
end
end
resources :merge_requests, concerns: :awardable, except: [:new, :create, :show], constraints: { id: /\d+/ } do
......@@ -347,6 +353,17 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
end
Gitlab.ee do
resources :path_locks, only: [:index, :destroy] do
collection do
post :toggle
end
end
get '/service_desk' => 'service_desk#show', as: :service_desk
put '/service_desk' => 'service_desk#update', as: :service_desk_refresh
end
resource :variables, only: [:show, :update]
resources :triggers, only: [:index, :create, :edit, :update, :destroy]
......@@ -380,6 +397,11 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
get :failures
get :status
get :test_report
Gitlab.ee do
get :security
get :licenses
end
end
member do
......@@ -514,11 +536,24 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
get :realtime_changes
post :create_merge_request
get :discussions, format: :json
Gitlab.ee do
get 'designs(/*vueroute)', to: 'issues#designs', as: :designs, format: false
end
end
collection do
post :bulk_update
post :import_csv
Gitlab.ee do
post :export_csv
get :service_desk
end
end
Gitlab.ee do
resources :issue_links, only: [:index, :create, :destroy], as: 'links', path: 'links'
end
end
......@@ -594,15 +629,6 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
Gitlab.ee do
resources :managed_licenses, only: [:index, :show, :new, :create, :edit, :update, :destroy]
end
# Legacy routes.
# Introduced in 12.0.
# Should be removed after 12.1
Gitlab::Routing.redirect_legacy_paths(self, :settings, :branches, :tags,
:network, :graphs, :autocomplete_sources,
:project_members, :deploy_keys, :deploy_tokens,
:labels, :milestones, :services, :boards, :releases,
:forks, :group_links, :import, :avatar)
end
resources(:projects,
......@@ -627,4 +653,22 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
end
end
# Legacy routes.
# Introduced in 12.0.
# Should be removed after 12.1
scope(path: '*namespace_id',
as: :namespace,
namespace_id: Gitlab::PathRegex.full_namespace_route_regex) do
scope(path: ':project_id',
constraints: { project_id: Gitlab::PathRegex.project_route_regex },
module: :projects,
as: :project) do
Gitlab::Routing.redirect_legacy_paths(self, :settings, :branches, :tags,
:network, :graphs, :autocomplete_sources,
:project_members, :deploy_keys, :deploy_tokens,
:labels, :milestones, :services, :boards, :releases,
:forks, :group_links, :import, :avatar)
end
end
end
# frozen_string_literal: true
class AddSetupForCompanyToUserPreferences < ActiveRecord::Migration[5.2]
DOWNTIME = false
def change
add_column :user_preferences, :setup_for_company, :boolean
end
end
......@@ -3754,6 +3754,7 @@ ActiveRecord::Schema.define(version: 2019_11_05_094625) do
t.boolean "time_format_in_24h"
t.string "projects_sort", limit: 64
t.boolean "show_whitespace_in_diffs", default: true, null: false
t.boolean "setup_for_company"
t.index ["user_id"], name: "index_user_preferences_on_user_id", unique: true
end
......
......@@ -2,12 +2,17 @@
module Constraints
class ProjectUrlConstrainer
def matches?(request)
def matches?(request, existence_check: true)
namespace_path = request.params[:namespace_id]
project_path = request.params[:project_id] || request.params[:id]
full_path = [namespace_path, project_path].join('/')
ProjectPathValidator.valid_path?(full_path)
return false unless ProjectPathValidator.valid_path?(full_path)
return true unless existence_check
# We intentionally allow SELECT(*) here so result of this query can be used
# as cache for further Project.find_by_full_path calls within request
Project.find_by_full_path(full_path, follow_redirects: request.get?).present?
end
end
end
......@@ -10,7 +10,7 @@ module Gitlab
RoutesNotFound = Class.new(StandardError)
def draw(routes_name)
drawn_any = draw_ee(routes_name) | draw_ce(routes_name)
drawn_any = draw_ce(routes_name) | draw_ee(routes_name)
drawn_any || raise(RoutesNotFound.new("Cannot find #{routes_name}"))
end
......
......@@ -1947,6 +1947,9 @@ msgstr ""
msgid "Archiving the project will make it entirely read-only. It is hidden from the dashboard and doesn't show up in searches. <strong>The repository cannot be committed to, and no issues, comments or other entities can be created.</strong>"
msgstr ""
msgid "Are you setting up GitLab for a company?"
msgstr ""
msgid "Are you sure that you want to archive this project?"
msgstr ""
......@@ -9143,7 +9146,7 @@ msgstr ""
msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
msgstr ""
msgid "In order to tailor your experience with GitLab<br>we would like to know a bit more about you."
msgid "In order to tailor your experience with GitLab we<br>would like to know a bit more about you."
msgstr ""
msgid "In the next step, you'll be able to select the projects you want to import."
......@@ -19090,7 +19093,7 @@ msgstr ""
msgid "Welcome to GitLab"
msgstr ""
msgid "Welcome to GitLab %{username}!"
msgid "Welcome to GitLab @%{username}!"
msgstr ""
msgid "Welcome to the Guided GitLab Tour"
......
......@@ -186,7 +186,7 @@ describe ApplicationController do
expect(response).to have_gitlab_http_status(404)
end
it 'redirects to login page via authenticate_user! if not authenticated' do
it 'redirects to login page if not authenticated' do
get :index
expect(response).to redirect_to new_user_session_path
......@@ -827,7 +827,7 @@ describe ApplicationController do
end
end
describe '#require_role' do
describe '#required_signup_info' do
controller(described_class) do
def index; end
end
......@@ -849,7 +849,7 @@ describe ApplicationController do
it { is_expected.to redirect_to users_sign_up_welcome_path }
end
context 'experiment enabled and user without a role' do
context 'experiment enabled and user without a required role' do
before do
sign_in(user)
get :index
......@@ -858,7 +858,7 @@ describe ApplicationController do
it { is_expected.not_to redirect_to users_sign_up_welcome_path }
end
context 'experiment disabled and user with required role' do
context 'experiment disabled' do
let(:experiment_enabled) { false }
before do
......
......@@ -142,7 +142,7 @@ describe Projects::CommitsController do
context 'token authentication' do
context 'public project' do
it_behaves_like 'authenticates sessionless user', :show, :atom, public: true do
it_behaves_like 'authenticates sessionless user', :show, :atom, { public: true, ignore_incrementing: true } do
before do
public_project = create(:project, :repository, :public)
......@@ -152,7 +152,7 @@ describe Projects::CommitsController do
end
context 'private project' do
it_behaves_like 'authenticates sessionless user', :show, :atom, public: false do
it_behaves_like 'authenticates sessionless user', :show, :atom, { public: false, ignore_incrementing: true } do
before do
private_project = create(:project, :repository, :private)
private_project.add_maintainer(user)
......
......@@ -146,7 +146,7 @@ describe Projects::ErrorTrackingController do
it 'redirects to sign-in page' do
post :list_projects, params: list_projects_params
expect(response).to have_gitlab_http_status(:unauthorized)
expect(response).to have_gitlab_http_status(:redirect)
end
end
......
......@@ -1441,7 +1441,7 @@ describe Projects::IssuesController do
context 'private project with token authentication' do
let(:private_project) { create(:project, :private) }
it_behaves_like 'authenticates sessionless user', :index, :atom do
it_behaves_like 'authenticates sessionless user', :index, :atom, ignore_incrementing: true do
before do
default_params.merge!(project_id: private_project, namespace_id: private_project.namespace)
......@@ -1449,7 +1449,7 @@ describe Projects::IssuesController do
end
end
it_behaves_like 'authenticates sessionless user', :calendar, :ics do
it_behaves_like 'authenticates sessionless user', :calendar, :ics, ignore_incrementing: true do
before do
default_params.merge!(project_id: private_project, namespace_id: private_project.namespace)
......
......@@ -111,8 +111,8 @@ describe Projects::ReleasesController do
context 'when the project is private and the user is not logged in' do
let(:project) { private_project }
it 'returns a 401' do
expect(response).to have_gitlab_http_status(:unauthorized)
it 'returns a redirect' do
expect(response).to have_gitlab_http_status(:redirect)
end
end
end
......
......@@ -41,7 +41,7 @@ describe Projects::TagsController do
context 'private project with token authentication' do
let(:private_project) { create(:project, :repository, :private) }
it_behaves_like 'authenticates sessionless user', :index, :atom do
it_behaves_like 'authenticates sessionless user', :index, :atom, ignore_incrementing: true do
before do
default_params.merge!(project_id: private_project, namespace_id: private_project.namespace)
......
......@@ -1149,7 +1149,7 @@ describe ProjectsController do
context 'private project with token authentication' do
let(:private_project) { create(:project, :private) }
it_behaves_like 'authenticates sessionless user', :show, :atom do
it_behaves_like 'authenticates sessionless user', :show, :atom, ignore_incrementing: true do
before do
default_params.merge!(id: private_project, namespace_id: private_project.namespace)
......
......@@ -381,7 +381,7 @@ describe RegistrationsController do
end
end
describe '#update_role' do
describe '#update_registration' do
before do
stub_experiment(signup_flow: true)
stub_experiment_for_user(signup_flow: true)
......@@ -395,7 +395,7 @@ describe RegistrationsController do
label: anything,
property: 'experimental_group'
)
patch :update_role, params: { user: { name: 'New name', role: 'software_developer' } }
patch :update_registration, params: { user: { name: 'New name', role: 'software_developer', setup_for_company: 'false' } }
end
end
end
......@@ -819,7 +819,10 @@ describe 'Pipelines', :js do
context 'when project is private' do
let(:project) { create(:project, :private, :repository) }
it { expect(page).to have_content 'You need to sign in' }
it 'redirects the user to sign_in and displays the flash alert' do
expect(page).to have_content 'You need to sign in'
expect(page.current_path).to eq("/users/sign_in")
end
end
end
......
......@@ -15,7 +15,7 @@ describe 'User views tags', :feature do
it do
visit project_tags_path(project, format: :atom)
expect(page).to have_gitlab_http_status(401)
expect(page.current_path).to eq("/users/sign_in")
end
end
......
......@@ -441,11 +441,13 @@ describe 'With experimental flow' do
fill_in 'user_name', with: 'New name'
select 'Software Developer', from: 'user_role'
choose 'user_setup_for_company_true'
click_button 'Get started!'
new_user = User.find_by_username(new_user.username)
expect(new_user.name).to eq 'New name'
expect(new_user.software_developer_role?).to be_truthy
expect(new_user.setup_for_company).to be_truthy
expect(page).to have_current_path(new_project_path)
end
end
......
......@@ -14,15 +14,42 @@ describe Constraints::ProjectUrlConstrainer do
end
context 'invalid request' do
context "non-existing project" do
let(:request) { build_request('foo', 'bar') }
it { expect(subject.matches?(request)).to be_falsey }
context 'existence_check is false' do
it { expect(subject.matches?(request, existence_check: false)).to be_truthy }
end
end
context "project id ending with .git" do
let(:request) { build_request(namespace.full_path, project.path + '.git') }
it { expect(subject.matches?(request)).to be_falsey }
end
end
context 'when the request matches a redirect route' do
let(:old_project_path) { 'old_project_path' }
let!(:redirect_route) { project.redirect_routes.create!(path: "#{namespace.full_path}/#{old_project_path}") }
context 'and is a GET request' do
let(:request) { build_request(namespace.full_path, old_project_path) }
it { expect(subject.matches?(request)).to be_truthy }
end
context 'and is NOT a GET request' do
let(:request) { build_request(namespace.full_path, old_project_path, 'POST') }
it { expect(subject.matches?(request)).to be_falsey }
end
end
end
def build_request(namespace, project)
double(:request, params: { namespace_id: namespace, id: project })
def build_request(namespace, project, method = 'GET')
double(:request,
'get?': (method == 'GET'),
params: { namespace_id: namespace, id: project })
end
end
......@@ -3,6 +3,18 @@
require 'spec_helper'
describe LfsObject do
context 'scopes' do
describe '.not_existing_in_project' do
it 'contains only lfs objects not linked to the project' do
project = create(:project)
create(:lfs_objects_project, project: project)
other_lfs_object = create(:lfs_object)
expect(described_class.not_linked_to_project(project)).to contain_exactly(other_lfs_object)
end
end
end
it 'has a distinct has_many :projects relation through lfs_objects_projects' do
lfs_object = create(:lfs_object)
project = create(:project)
......
# frozen_string_literal: true
require 'spec_helper'
describe Projects::BlobController do
let(:project) { create(:project, :private, :repository) }
let(:namespace) { project.namespace }
context 'anonymous user views blob in inaccessible project' do
context 'with default HTML format' do
before do
get namespace_project_blob_path(namespace_id: namespace, project_id: project, id: 'master/README.md')
end
context 'when project is private' do
it { expect(response).to have_gitlab_http_status(:redirect) }
end
context 'when project does not exist' do
let(:namespace) { 'non_existent_namespace' }
let(:project) { 'non_existent_project' }
it { expect(response).to have_gitlab_http_status(:redirect) }
end
end
context 'with JSON format' do
before do
get namespace_project_blob_path(namespace_id: namespace, project_id: project, id: 'master/README.md', format: :json)
end
context 'when project is private' do
it { expect(response).to have_gitlab_http_status(:unauthorized) }
end
context 'when project does not exist' do
let(:namespace) { 'non_existent_namespace' }
let(:project) { 'non_existent_project' }
it { expect(response).to have_gitlab_http_status(:unauthorized) }
end
end
end
end
......@@ -776,6 +776,10 @@ describe 'project routing' do
it 'routes when :template_type is `issue`' do
expect(get(show_with_template_type('issue'))).to route_to('projects/templates#show', namespace_id: 'gitlab', project_id: 'gitlabhq', template_type: 'issue', key: 'template_name', format: 'json')
end
it 'routes to application#route_not_found when :template_type is unknown' do
expect(get(show_with_template_type('invalid'))).to route_to('application#route_not_found', unmatched_route: 'gitlab/gitlabhq/templates/invalid/template_name')
end
end
end
......
......@@ -16,6 +16,13 @@ describe Projects::LfsPointers::LfsLinkService do
end
describe '#execute' do
it 'raises an error when trying to link too many objects at once' do
oids = Array.new(described_class::MAX_OIDS) { |i| "oid-#{i}" }
oids << 'the straw'
expect { subject.execute(oids) }.to raise_error(described_class::TooManyOidsError)
end
it 'links existing lfs objects to the project' do
expect(project.all_lfs_objects.count).to eq 2
......@@ -28,7 +35,7 @@ describe Projects::LfsPointers::LfsLinkService do
it 'returns linked oids' do
linked = lfs_objects_project.map(&:lfs_object).map(&:oid) << new_lfs_object.oid
expect(subject.execute(new_oid_list.keys)).to eq linked
expect(subject.execute(new_oid_list.keys)).to contain_exactly(*linked)
end
it 'links in batches' do
......@@ -48,5 +55,26 @@ describe Projects::LfsPointers::LfsLinkService do
expect(project.all_lfs_objects.count).to eq 9
expect(linked.size).to eq 7
end
it 'only queries for the batch that will be processed', :aggregate_failures do
stub_const("#{described_class}::BATCH_SIZE", 1)
oids = %w(one two)
expect(LfsObject).to receive(:where).with(oid: %w(one)).once.and_call_original
expect(LfsObject).to receive(:where).with(oid: %w(two)).once.and_call_original
subject.execute(oids)
end
it 'only queries 3 times' do
# make sure that we don't count the queries in the setup
new_oid_list
# These are repeated for each batch of oids: maximum (MAX_OIDS / BATCH_SIZE) times
# 1. Load the batch of lfs object ids that we might know already
# 2. Load the objects that have not been linked to the project yet
# 3. Insert the lfs_objects_projects for that batch
expect { subject.execute(new_oid_list.keys) }.not_to exceed_query_limit(3)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Users::SignupService do
let(:user) { create(:user, setup_for_company: true) }
describe '#execute' do
context 'when updating name' do
it 'updates the name attribute' do
result = update_user(user, name: 'New Name')
expect(result).to eq(status: :success)
expect(user.reload.name).to eq('New Name')
end
it 'returns an error result when name is missing' do
result = update_user(user, name: '')
expect(user.reload.name).not_to be_blank
expect(result[:status]).to eq(:error)
expect(result[:message]).to include("Name can't be blank")
end
end
context 'when updating role' do
it 'updates the role attribute' do
result = update_user(user, role: 'development_team_lead')
expect(result).to eq(status: :success)
expect(user.reload.role).to eq('development_team_lead')
end
it 'returns an error result when role is missing' do
result = update_user(user, role: '')
expect(user.reload.role).not_to be_blank
expect(result[:status]).to eq(:error)
expect(result[:message]).to eq("Role can't be blank")
end
end
context 'when updating setup_for_company' do
it 'updates the setup_for_company attribute' do
result = update_user(user, setup_for_company: 'false')
expect(result).to eq(status: :success)
expect(user.reload.setup_for_company).to be(false)
end
it 'returns an error result when setup_for_company is missing' do
result = update_user(user, setup_for_company: '')
expect(user.reload.setup_for_company).not_to be_blank
expect(result[:status]).to eq(:error)
expect(result[:message]).to eq("Setup for company can't be blank")
end
end
def update_user(user, opts)
described_class.new(user, opts).execute
end
end
end
......@@ -34,8 +34,15 @@ shared_examples 'authenticates sessionless user' do |path, format, params|
context 'when the personal access token has no api scope', unless: params[:public] do
it 'does not log the user in' do
expect(authentication_metrics)
.to increment(:user_unauthenticated_counter)
# Several instances of where these specs are shared route the request
# through ApplicationController#route_not_found which does not involve
# the usual auth code from Devise, so does not increment the
# :user_unauthenticated_counter
#
unless params[:ignore_incrementing]
expect(authentication_metrics)
.to increment(:user_unauthenticated_counter)
end
personal_access_token.update(scopes: [:read_user])
......@@ -84,8 +91,15 @@ shared_examples 'authenticates sessionless user' do |path, format, params|
end
it "doesn't log the user in otherwise", unless: params[:public] do
expect(authentication_metrics)
.to increment(:user_unauthenticated_counter)
# Several instances of where these specs are shared route the request
# through ApplicationController#route_not_found which does not involve
# the usual auth code from Devise, so does not increment the
# :user_unauthenticated_counter
#
unless params[:ignore_incrementing]
expect(authentication_metrics)
.to increment(:user_unauthenticated_counter)
end
get path, params: default_params.merge(private_token: 'token')
......
......@@ -39,7 +39,7 @@ shared_examples 'todos actions' do
post_create
end.to change { user.todos.count }.by(0)
expect(response).to have_gitlab_http_status(parent.is_a?(Group) ? 401 : 302)
expect(response).to have_gitlab_http_status(302)
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment