Commit f24c43da authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 038949853ce8
......@@ -47,23 +47,13 @@ def self.project_id_batches_rollback(&block)
end
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord
def self.legacy_attachments_relation
Upload.joins(<<~SQL).where('projects.storage_version < :version OR projects.storage_version IS NULL', version: Project::HASHED_STORAGE_FEATURES[:attachments])
JOIN projects
ON (uploads.model_type='Project' AND uploads.model_id=projects.id)
SQL
Upload.inner_join_local_uploads_projects.merge(Project.without_storage_feature(:attachments))
end
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord
def self.hashed_attachments_relation
Upload.joins(<<~SQL).where('projects.storage_version >= :version', version: Project::HASHED_STORAGE_FEATURES[:attachments])
JOIN projects
ON (uploads.model_type='Project' AND uploads.model_id=projects.id)
SQL
Upload.inner_join_local_uploads_projects.merge(Project.with_storage_feature(:attachments))
end
# rubocop: enable CodeReuse/ActiveRecord
def self.relation_summary(relation_name, relation)
relation_count = relation.count
......
......@@ -146,7 +146,10 @@ def has_normalized_ws_text?(text, wait: Capybara.default_max_wait_time)
end
def finished_loading?
has_no_css?('.fa-spinner', wait: Capybara.default_max_wait_time)
# The number of selectors should be able to be reduced after
# migration to the new spinner is complete.
# https://gitlab.com/groups/gitlab-org/-/epics/956
has_no_css?('.gl-spinner, .fa-spinner, .spinner', wait: Capybara.default_max_wait_time)
end
def finished_loading_block?
......
......@@ -31,7 +31,7 @@ def expand_select_list
end
def wait_for_search_to_complete
has_css?('.select2-active')
has_css?('.select2-active', wait: 1)
has_no_css?('.select2-active', wait: 30)
end
end
......
......@@ -6,7 +6,7 @@ module Settings
module Common
# Click the Expand button present in the specified section
#
# @param [Symbol] and `element` name defined in a `view` block
# @param [Symbol] element_name `element` name defined in a `view` block
def expand_section(element_name)
within_element(element_name) do
# Because it is possible to click the button before the JS toggle code is bound
......@@ -14,6 +14,7 @@ def expand_section(element_name)
click_button 'Expand' unless has_css?('button', text: 'Collapse', wait: 1)
has_content?('Collapse')
finished_loading?
end
yield if block_given?
......
......@@ -5,6 +5,10 @@
describe 'Internal Snippets', :js do
let(:internal_snippet) { create(:personal_snippet, :internal) }
before do
stub_feature_flags(snippets_vue: false)
end
describe 'normal user' do
before do
sign_in(create(:user))
......
......@@ -16,6 +16,7 @@
let!(:other_note) { create(:note_on_personal_snippet) }
before do
stub_feature_flags(snippets_vue: false)
sign_in user
visit snippet_path(snippet)
......
......@@ -6,6 +6,7 @@
let(:user) { create(:user) }
before do
stub_feature_flags(snippets_vue: false)
sign_in(user)
end
......
......@@ -3,6 +3,10 @@
require 'spec_helper'
describe 'Public Snippets', :js do
before do
stub_feature_flags(snippets_vue: false)
end
it 'Unauthenticated user should see public snippets' do
public_snippet = create(:personal_snippet, :public)
......
......@@ -6,6 +6,10 @@
let(:project) { create(:project, :repository) }
let(:snippet) { create(:personal_snippet, :public, file_name: file_name, content: content) }
before do
stub_feature_flags(snippets_vue: false)
end
context 'Ruby file' do
let(:file_name) { 'popen.rb' }
let(:content) { project.repository.blob_at('master', 'files/ruby/popen.rb').data }
......
......@@ -7,6 +7,7 @@
before do
stub_feature_flags(allow_possible_spam: false)
stub_feature_flags(snippets_vue: false)
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
Gitlab::CurrentSettings.update!(
......
......@@ -8,6 +8,7 @@
let(:user) { create(:user) }
before do
stub_feature_flags(snippets_vue: false)
sign_in(user)
visit new_snippet_path
end
......
......@@ -10,6 +10,8 @@
before do
sign_in(user)
stub_feature_flags(snippets_vue: false)
visit snippet_path(snippet)
end
......
......@@ -12,6 +12,7 @@
let(:snippet) { create(:personal_snippet, :public, file_name: file_name, content: content, author: user) }
before do
stub_feature_flags(snippets_vue: false)
sign_in(user)
visit edit_snippet_path(snippet)
......
......@@ -6,11 +6,38 @@
context 'when the project has snippets' do
let(:project) { create(:project, :public) }
let!(:snippets) { create_list(:project_snippet, 2, :public, author: project.owner, project: project) }
before do
allow(Snippet).to receive(:default_per_page).and_return(1)
visit snippets_path(username: project.owner.username)
visit project_snippets_path(project)
end
it_behaves_like 'paginated snippets'
end
describe 'rendering engine' do
let_it_be(:snippet) { create(:personal_snippet, :public) }
let(:snippets_vue_feature_flag_enabled) { true }
before do
stub_feature_flags(snippets_vue: snippets_vue_feature_flag_enabled)
visit snippet_path(snippet)
end
it 'renders Vue application' do
expect(page).to have_selector('#js-snippet-view')
expect(page).not_to have_selector('.personal-snippets')
end
context 'when feature flag is disabled' do
let(:snippets_vue_feature_flag_enabled) { false }
it 'renders HAML application and not Vue' do
expect(page).not_to have_selector('#js-snippet-view')
expect(page).to have_selector('.personal-snippets')
end
end
end
end
......@@ -32,13 +32,13 @@
let(:params) { { order_by: order_by, sort: sort } }
let!(:deployment_1) { create(:deployment, :success, project: project, iid: 11, ref: 'master', created_at: Time.now, updated_at: Time.now) }
let!(:deployment_1) { create(:deployment, :success, project: project, iid: 11, ref: 'master', created_at: 2.days.ago, updated_at: Time.now) }
let!(:deployment_2) { create(:deployment, :success, project: project, iid: 12, ref: 'feature', created_at: 1.day.ago, updated_at: 2.hours.ago) }
let!(:deployment_3) { create(:deployment, :success, project: project, iid: 8, ref: 'patch', created_at: 2.days.ago, updated_at: 1.hour.ago) }
let!(:deployment_3) { create(:deployment, :success, project: project, iid: 8, ref: 'patch', created_at: Time.now, updated_at: 1.hour.ago) }
where(:order_by, :sort, :ordered_deployments) do
'created_at' | 'asc' | [:deployment_3, :deployment_2, :deployment_1]
'created_at' | 'desc' | [:deployment_1, :deployment_2, :deployment_3]
'created_at' | 'asc' | [:deployment_1, :deployment_2, :deployment_3]
'created_at' | 'desc' | [:deployment_3, :deployment_2, :deployment_1]
'id' | 'asc' | [:deployment_1, :deployment_2, :deployment_3]
'id' | 'desc' | [:deployment_3, :deployment_2, :deployment_1]
'iid' | 'asc' | [:deployment_3, :deployment_1, :deployment_2]
......@@ -57,5 +57,41 @@
end
end
end
describe 'transform `created_at` sorting to `id` sorting' do
let(:params) { { order_by: 'created_at', sort: 'asc' } }
it 'sorts by only one column' do
expect(subject.order_values.size).to eq(1)
end
it 'sorts by `id`' do
expect(subject.order_values.first.to_sql).to eq(Deployment.arel_table[:id].asc.to_sql)
end
end
describe 'tie-breaker for `updated_at` sorting' do
let(:params) { { order_by: 'updated_at', sort: 'asc' } }
it 'sorts by two columns' do
expect(subject.order_values.size).to eq(2)
end
it 'adds `id` sorting as the second order column' do
order_value = subject.order_values[1]
expect(order_value.to_sql).to eq(Deployment.arel_table[:id].desc.to_sql)
end
it 'uses the `id DESC` as tie-breaker when ordering' do
updated_at = Time.now
deployment_1 = create(:deployment, :success, project: project, updated_at: updated_at)
deployment_2 = create(:deployment, :success, project: project, updated_at: updated_at)
deployment_3 = create(:deployment, :success, project: project, updated_at: updated_at)
expect(subject).to eq([deployment_3, deployment_2, deployment_1])
end
end
end
end
......@@ -17,6 +17,7 @@
end
before do
stub_feature_flags(snippets_vue: false)
sign_in(admin)
allow(Discussion).to receive(:build_discussion_id).and_return(['discussionid:ceterumcenseo'])
end
......
......@@ -38,28 +38,44 @@
.and_return(double(execute: kubernetes_namespace))
end
context 'and the knative version role binding is missing' do
context 'and the knative-serving namespace is missing' do
before do
allow(Clusters::KnativeVersionRoleBindingFinder).to receive(:new)
.and_return(double(execute: nil))
allow(Clusters::KnativeServingNamespaceFinder).to receive(:new)
.and_return(double(execute: false))
end
it { is_expected.to be_truthy }
end
context 'and the knative version role binding already exists' do
context 'and the knative-serving namespace exists' do
before do
allow(Clusters::KnativeVersionRoleBindingFinder).to receive(:new)
allow(Clusters::KnativeServingNamespaceFinder).to receive(:new)
.and_return(double(execute: true))
end
it { is_expected.to be_falsey }
context 'and the service_account_token is blank' do
let(:kubernetes_namespace) { instance_double(Clusters::KubernetesNamespace, service_account_token: nil) }
context 'and the knative version role binding is missing' do
before do
allow(Clusters::KnativeVersionRoleBindingFinder).to receive(:new)
.and_return(double(execute: nil))
end
it { is_expected.to be_truthy }
end
context 'and the knative version role binding already exists' do
before do
allow(Clusters::KnativeVersionRoleBindingFinder).to receive(:new)
.and_return(double(execute: true))
end
it { is_expected.to be_falsey }
context 'and the service_account_token is blank' do
let(:kubernetes_namespace) { instance_double(Clusters::KubernetesNamespace, service_account_token: nil) }
it { is_expected.to be_truthy }
end
end
end
end
end
......
......@@ -53,6 +53,16 @@
end
describe '#prometheus_client' do
shared_examples 'exception caught for prometheus client' do
before do
allow(kube_client).to receive(:proxy_url).and_raise(exception)
end
it 'returns nil' do
expect(subject.prometheus_client).to be_nil
end
end
context 'cluster is nil' do
it 'returns nil' do
expect(subject.cluster).to be_nil
......@@ -98,12 +108,18 @@
end
context 'when cluster is not reachable' do
before do
allow(kube_client).to receive(:proxy_url).and_raise(Kubeclient::HttpError.new(401, 'Unauthorized', nil))
it_behaves_like 'exception caught for prometheus client' do
let(:exception) { Kubeclient::HttpError.new(401, 'Unauthorized', nil) }
end
end
context 'when there is a socket error while contacting cluster' do
it_behaves_like 'exception caught for prometheus client' do
let(:exception) { Errno::ECONNREFUSED }
end
it 'returns nil' do
expect(subject.prometheus_client).to be_nil
it_behaves_like 'exception caught for prometheus client' do
let(:exception) { Errno::ECONNRESET }
end
end
end
......@@ -289,4 +305,28 @@
end
end
end
describe '#configured?' do
let(:prometheus) { create(:clusters_applications_prometheus, :installed, cluster: cluster) }
subject { prometheus.configured? }
context 'when a kubenetes client is present' do
let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
it { is_expected.to be_truthy }
context 'when it is not availalble' do
let(:prometheus) { create(:clusters_applications_prometheus, cluster: cluster) }
it { is_expected.to be_falsey }
end
end
context 'when a kubenetes client is not present' do
let(:cluster) { create(:cluster) }
it { is_expected.to be_falsy }
end
end
end
......@@ -824,6 +824,14 @@
context 'and no deployments' do
it { is_expected.to be_truthy }
end
context 'and the prometheus adapter is not configured' do
before do
allow(environment.prometheus_adapter).to receive(:configured?).and_return(false)
end
it { is_expected.to be_falsy }
end
end
context 'without a monitoring service' do
......@@ -858,6 +866,14 @@
is_expected.to eq(:fake_metrics)
end
context 'and the prometheus client is not present' do
before do
allow(environment.prometheus_adapter).to receive(:promethus_client).and_return(nil)
end
it { is_expected.to be_nil }
end
end
context 'when the environment does not have metrics' do
......
......@@ -332,4 +332,40 @@ def expect_deployments(ordered_deployments)
end
end
end
context 'prevent N + 1 queries' do
context 'when the endpoint returns multiple records' do
let(:project) { create(:project) }
def create_record
create(:deployment, :success, project: project)
end
def request_with_query_count
ActiveRecord::QueryRecorder.new { trigger_request }.count
end
def trigger_request
get api("/projects/#{project.id}/deployments?order_by=updated_at&sort=asc", user)
end
before do
create_record
end
it 'succeeds' do
trigger_request
expect(response).to have_gitlab_http_status(200)
expect(json_response.size).to eq(1)
end
it 'does not increase the query count' do
expect { create_record }.not_to change { request_with_query_count }
expect(json_response.size).to eq(2)
end
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