Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-02-20 16:49:51 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-02-20 16:49:51 +0300
commit71786ddc8e28fbd3cb3fcc4b3ff15e5962a1c82e (patch)
tree6a2d93ef3fb2d353bb7739e4b57e6541f51cdd71 /spec/requests/projects
parenta7253423e3403b8c08f8a161e5937e1488f5f407 (diff)
Add latest changes from gitlab-org/gitlab@15-9-stable-eev15.9.0-rc42
Diffstat (limited to 'spec/requests/projects')
-rw-r--r--spec/requests/projects/airflow/dags_controller_spec.rb105
-rw-r--r--spec/requests/projects/blob_spec.rb87
-rw-r--r--spec/requests/projects/google_cloud/databases_controller_spec.rb84
-rw-r--r--spec/requests/projects/ml/experiments_controller_spec.rb152
-rw-r--r--spec/requests/projects/network_controller_spec.rb11
-rw-r--r--spec/requests/projects/noteable_notes_spec.rb36
-rw-r--r--spec/requests/projects/pipelines_controller_spec.rb26
-rw-r--r--spec/requests/projects/releases_controller_spec.rb40
8 files changed, 463 insertions, 78 deletions
diff --git a/spec/requests/projects/airflow/dags_controller_spec.rb b/spec/requests/projects/airflow/dags_controller_spec.rb
new file mode 100644
index 00000000000..2dcedf5f128
--- /dev/null
+++ b/spec/requests/projects/airflow/dags_controller_spec.rb
@@ -0,0 +1,105 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::Airflow::DagsController, feature_category: :dataops do
+ let_it_be(:non_member) { create(:user) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group) { create(:group).tap { |p| p.add_developer(user) } }
+ let_it_be(:project) { create(:project, group: group).tap { |p| p.add_developer(user) } }
+
+ let(:current_user) { user }
+ let(:feature_flag) { true }
+
+ let_it_be(:dags) do
+ create_list(:airflow_dags, 5, project: project)
+ end
+
+ let(:params) { { namespace_id: project.namespace.to_param, project_id: project } }
+ let(:extra_params) { {} }
+
+ before do
+ sign_in(current_user) if current_user
+ stub_feature_flags(airflow_dags: false)
+ stub_feature_flags(airflow_dags: project) if feature_flag
+ list_dags
+ end
+
+ shared_examples 'returns a 404 if feature flag disabled' do
+ context 'when :airflow_dags disabled' do
+ let(:feature_flag) { false }
+
+ it 'is 404' do
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ describe 'GET index' do
+ it 'renders the template' do
+ expect(response).to render_template('projects/airflow/dags/index')
+ end
+
+ describe 'pagination' do
+ before do
+ stub_const("Projects::Airflow::DagsController::MAX_DAGS_PER_PAGE", 2)
+ dags
+
+ list_dags
+ end
+
+ context 'when out of bounds' do
+ let(:params) { extra_params.merge(page: 10000) }
+
+ it 'redirects to last page' do
+ last_page = (dags.size + 1) / 2
+ expect(response).to redirect_to(project_airflow_dags_path(project, page: last_page))
+ end
+ end
+
+ context 'when bad page' do
+ let(:params) { extra_params.merge(page: 's') }
+
+ it 'uses first page' do
+ expect(assigns(:pagination)).to include(
+ page: 1,
+ is_last_page: false,
+ per_page: 2,
+ total_items: dags.size)
+ end
+ end
+ end
+
+ it 'does not perform N+1 sql queries' do
+ control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) { list_dags }
+
+ create_list(:airflow_dags, 1, project: project)
+
+ expect { list_dags }.not_to exceed_all_query_limit(control_count)
+ end
+
+ context 'when user is not logged in' do
+ let(:current_user) { nil }
+
+ it 'redirects to login' do
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+
+ context 'when user is not a member' do
+ let(:current_user) { non_member }
+
+ it 'returns a 404' do
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ it_behaves_like 'returns a 404 if feature flag disabled'
+ end
+
+ private
+
+ def list_dags
+ get project_airflow_dags_path(project), params: params
+ end
+end
diff --git a/spec/requests/projects/blob_spec.rb b/spec/requests/projects/blob_spec.rb
new file mode 100644
index 00000000000..7d62619e76a
--- /dev/null
+++ b/spec/requests/projects/blob_spec.rb
@@ -0,0 +1,87 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Blobs', feature_category: :source_code_management do
+ let_it_be(:project) { create(:project, :public, :repository, lfs: true) }
+
+ describe 'GET /:namespace_id/:project_id/-/blob/:id' do
+ subject(:request) do
+ get namespace_project_blob_path(namespace_id: project.namespace, project_id: project, id: id)
+ end
+
+ context 'with LFS file' do
+ let(:id) { 'master/files/lfs/lfs_object.iso' }
+ let(:object_store_host) { 'http://127.0.0.1:9000' }
+ let(:connect_src) do
+ csp = response.headers['Content-Security-Policy']
+ csp.split('; ').find { |src| src.starts_with?('connect-src') }
+ end
+
+ let(:gitlab_config) do
+ Gitlab.config.gitlab.deep_merge(
+ 'content_security_policy' => {
+ 'enabled' => content_security_policy_enabled
+ }
+ )
+ end
+
+ let(:lfs_config) do
+ Gitlab.config.lfs.deep_merge(
+ 'enabled' => lfs_enabled,
+ 'object_store' => {
+ 'remote_directory' => 'lfs-objects',
+ 'enabled' => true,
+ 'proxy_download' => proxy_download,
+ 'connection' => {
+ 'endpoint' => object_store_host,
+ 'path_style' => true
+ }
+ }
+ )
+ end
+
+ before do
+ stub_config_setting(gitlab_config)
+ stub_lfs_setting(lfs_config)
+ stub_lfs_object_storage(proxy_download: proxy_download)
+
+ request
+ end
+
+ describe 'directly downloading lfs file' do
+ let(:lfs_enabled) { true }
+ let(:proxy_download) { false }
+ let(:content_security_policy_enabled) { true }
+
+ it { expect(response).to have_gitlab_http_status(:success) }
+
+ it { expect(connect_src).to include(object_store_host) }
+
+ context 'when lfs is disabled' do
+ let(:lfs_enabled) { false }
+
+ it { expect(response).to have_gitlab_http_status(:success) }
+
+ it { expect(connect_src).not_to include(object_store_host) }
+ end
+
+ context 'when content_security_policy is disabled' do
+ let(:content_security_policy_enabled) { false }
+
+ it { expect(response).to have_gitlab_http_status(:success) }
+
+ it { expect(connect_src).not_to include(object_store_host) }
+ end
+
+ context 'when proxy download is enabled' do
+ let(:proxy_download) { true }
+
+ it { expect(response).to have_gitlab_http_status(:success) }
+
+ it { expect(connect_src).not_to include(object_store_host) }
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/projects/google_cloud/databases_controller_spec.rb b/spec/requests/projects/google_cloud/databases_controller_spec.rb
index e91a51ce2ef..98e83610600 100644
--- a/spec/requests/projects/google_cloud/databases_controller_spec.rb
+++ b/spec/requests/projects/google_cloud/databases_controller_spec.rb
@@ -94,23 +94,33 @@ RSpec.describe Projects::GoogleCloud::DatabasesController, :snowplow, feature_ca
post project_google_cloud_databases_path(project)
end
- it 'calls EnableCloudsqlService and redirects on error' do
- expect_next_instance_of(::GoogleCloud::EnableCloudsqlService) do |service|
- expect(service).to receive(:execute)
- .and_return({ status: :error, message: 'error' })
+ context 'when EnableCloudsqlService fails' do
+ before do
+ allow_next_instance_of(::GoogleCloud::EnableCloudsqlService) do |service|
+ allow(service).to receive(:execute)
+ .and_return({ status: :error, message: 'error' })
+ end
end
- subject
+ it 'redirects and track event on error' do
+ subject
+
+ expect(response).to redirect_to(project_google_cloud_databases_path(project))
+
+ expect_snowplow_event(
+ category: 'Projects::GoogleCloud::DatabasesController',
+ action: 'error_enable_cloudsql_services',
+ label: nil,
+ project: project,
+ user: user
+ )
+ end
- expect(response).to redirect_to(project_google_cloud_databases_path(project))
+ it 'shows a flash alert' do
+ subject
- expect_snowplow_event(
- category: 'Projects::GoogleCloud::DatabasesController',
- action: 'error_enable_cloudsql_services',
- label: nil,
- project: project,
- user: user
- )
+ expect(flash[:alert]).to eq(s_('CloudSeed|Google Cloud Error - error'))
+ end
end
context 'when EnableCloudsqlService is successful' do
@@ -121,23 +131,33 @@ RSpec.describe Projects::GoogleCloud::DatabasesController, :snowplow, feature_ca
end
end
- it 'calls CreateCloudsqlInstanceService and redirects on error' do
- expect_next_instance_of(::GoogleCloud::CreateCloudsqlInstanceService) do |service|
- expect(service).to receive(:execute)
- .and_return({ status: :error, message: 'error' })
+ context 'when CreateCloudsqlInstanceService fails' do
+ before do
+ allow_next_instance_of(::GoogleCloud::CreateCloudsqlInstanceService) do |service|
+ allow(service).to receive(:execute)
+ .and_return({ status: :error, message: 'error' })
+ end
end
- subject
+ it 'redirects and track event on error' do
+ subject
- expect(response).to redirect_to(project_google_cloud_databases_path(project))
+ expect(response).to redirect_to(project_google_cloud_databases_path(project))
- expect_snowplow_event(
- category: 'Projects::GoogleCloud::DatabasesController',
- action: 'error_create_cloudsql_instance',
- label: nil,
- project: project,
- user: user
- )
+ expect_snowplow_event(
+ category: 'Projects::GoogleCloud::DatabasesController',
+ action: 'error_create_cloudsql_instance',
+ label: nil,
+ project: project,
+ user: user
+ )
+ end
+
+ it 'shows a flash warning' do
+ subject
+
+ expect(flash[:warning]).to eq(s_('CloudSeed|Google Cloud Error - error'))
+ end
end
context 'when CreateCloudsqlInstanceService is successful' do
@@ -161,6 +181,18 @@ RSpec.describe Projects::GoogleCloud::DatabasesController, :snowplow, feature_ca
user: user
)
end
+
+ it 'shows a flash notice' do
+ subject
+
+ expect(flash[:notice])
+ .to eq(
+ s_(
+ 'CloudSeed|Cloud SQL instance creation request successful. ' \
+ 'Expected resolution time is ~5 minutes.'
+ )
+ )
+ end
end
end
end
diff --git a/spec/requests/projects/ml/experiments_controller_spec.rb b/spec/requests/projects/ml/experiments_controller_spec.rb
index e8b6f806251..9b071efc1f1 100644
--- a/spec/requests/projects/ml/experiments_controller_spec.rb
+++ b/spec/requests/projects/ml/experiments_controller_spec.rb
@@ -38,31 +38,74 @@ RSpec.describe Projects::Ml::ExperimentsController, feature_category: :mlops do
end
describe 'GET index' do
- before do
- list_experiments
- end
+ describe 'renderering' do
+ before do
+ list_experiments
+ end
- it 'renders the template' do
- expect(response).to render_template('projects/ml/experiments/index')
+ it 'renders the template' do
+ expect(response).to render_template('projects/ml/experiments/index')
+ end
+
+ it 'does not perform N+1 sql queries' do
+ control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) { list_experiments }
+
+ create_list(:ml_experiments, 2, project: project, user: user)
+
+ expect { list_experiments }.not_to exceed_all_query_limit(control_count)
+ end
end
- it 'does not perform N+1 sql queries' do
- control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) { list_experiments }
+ describe 'pagination' do
+ let_it_be(:experiments) do
+ create_list(:ml_experiments, 3, project: project_with_feature)
+ end
- create_list(:ml_experiments, 2, project: project, user: user)
+ let(:params) { basic_params.merge(id: experiment.iid) }
- expect { list_experiments }.not_to exceed_all_query_limit(control_count)
+ before do
+ stub_const("Projects::Ml::ExperimentsController::MAX_EXPERIMENTS_PER_PAGE", 2)
+
+ list_experiments
+ end
+
+ it 'fetches only MAX_CANDIDATES_PER_PAGE candidates' do
+ expect(assigns(:experiments).size).to eq(2)
+ end
+
+ it 'paginates', :aggregate_failures do
+ page = assigns(:experiments)
+
+ expect(page.first).to eq(experiments.last)
+ expect(page.last).to eq(experiments[1])
+
+ new_params = params.merge(cursor: assigns(:page_info)[:end_cursor])
+
+ list_experiments(new_params)
+
+ new_page = assigns(:experiments)
+
+ expect(new_page.first).to eq(experiments.first)
+ end
end
context 'when :ml_experiment_tracking is disabled for the project' do
let(:project) { project_without_feature }
+ before do
+ list_experiments
+ end
+
it 'responds with a 404' do
expect(response).to have_gitlab_http_status(:not_found)
end
end
- it_behaves_like '404 if feature flag disabled'
+ it_behaves_like '404 if feature flag disabled' do
+ before do
+ list_experiments
+ end
+ end
end
describe 'GET show' do
@@ -75,36 +118,85 @@ RSpec.describe Projects::Ml::ExperimentsController, feature_category: :mlops do
end
describe 'pagination' do
- let_it_be(:candidates) { create_list(:ml_candidates, 5, experiment: experiment) }
+ let_it_be(:candidates) do
+ create_list(:ml_candidates, 5, experiment: experiment).tap do |c|
+ c.first.metrics.create!(name: 'metric1', value: 0.3)
+ c[1].metrics.create!(name: 'metric1', value: 0.2)
+ c.last.metrics.create!(name: 'metric1', value: 0.6)
+ end
+ end
+
+ let(:params) { basic_params.merge(id: experiment.iid) }
before do
stub_const("Projects::Ml::ExperimentsController::MAX_CANDIDATES_PER_PAGE", 2)
- candidates
show_experiment
end
- context 'when out of bounds' do
- let(:params) { basic_params.merge(id: experiment.iid, page: 10000) }
+ it 'fetches only MAX_CANDIDATES_PER_PAGE candidates' do
+ expect(assigns(:candidates).size).to eq(2)
+ end
+
+ it 'paginates' do
+ received = assigns(:page_info)
- it 'redirects to last page' do
- last_page = (experiment.candidates.size + 1) / 2
+ expect(received).to include({
+ has_next_page: true,
+ has_previous_page: false,
+ start_cursor: nil
+ })
+ end
+
+ context 'when order by metric' do
+ let(:params) do
+ {
+ order_by: "metric1",
+ order_by_type: "metric",
+ sort: "desc"
+ }
+ end
+
+ it 'paginates', :aggregate_failures do
+ page = assigns(:candidates)
+
+ expect(page.first).to eq(candidates.last)
+ expect(page.last).to eq(candidates.first)
+
+ new_params = params.merge(cursor: assigns(:page_info)[:end_cursor])
- expect(response).to redirect_to(project_ml_experiment_path(project, experiment.iid, page: last_page))
+ show_experiment(new_params)
+
+ new_page = assigns(:candidates)
+
+ expect(new_page.first).to eq(candidates[1])
end
end
+ end
- context 'when bad page' do
- let(:params) { basic_params.merge(id: experiment.iid, page: 's') }
+ describe 'search' do
+ let(:params) do
+ basic_params.merge(
+ id: experiment.iid,
+ name: 'some_name',
+ orderBy: 'name',
+ orderByType: 'metric',
+ sort: 'asc',
+ invalid: 'invalid'
+ )
+ end
- it 'uses first page' do
- expect(assigns(:pagination)).to include(
- page: 1,
- is_last_page: false,
- per_page: 2,
- total_items: experiment.candidates&.size
- )
+ it 'formats and filters the parameters' do
+ expect(Projects::Ml::CandidateFinder).to receive(:new).and_call_original do |exp, params|
+ expect(params.to_h).to include({
+ name: 'some_name',
+ order_by: 'name',
+ order_by_type: 'metric',
+ sort: 'asc'
+ })
end
+
+ show_experiment
end
end
@@ -125,11 +217,11 @@ RSpec.describe Projects::Ml::ExperimentsController, feature_category: :mlops do
private
- def show_experiment
- get project_ml_experiment_path(project, experiment.iid), params: params
+ def show_experiment(new_params = nil)
+ get project_ml_experiment_path(project, experiment.iid), params: new_params || params
end
- def list_experiments
- get project_ml_experiments_path(project), params: params
+ def list_experiments(new_params = nil)
+ get project_ml_experiments_path(project), params: new_params || params
end
end
diff --git a/spec/requests/projects/network_controller_spec.rb b/spec/requests/projects/network_controller_spec.rb
index 954f9655558..dee95c6e70e 100644
--- a/spec/requests/projects/network_controller_spec.rb
+++ b/spec/requests/projects/network_controller_spec.rb
@@ -35,17 +35,6 @@ RSpec.describe Projects::NetworkController, feature_category: :source_code_manag
subject
expect(assigns(:url)).to eq(project_network_path(project, ref, format: :json, ref_type: 'heads'))
end
-
- context 'when the use_ref_type_parameter flag is disabled' do
- before do
- stub_feature_flags(use_ref_type_parameter: false)
- end
-
- it 'assigns url without ref_type' do
- subject
- expect(assigns(:url)).to eq(project_network_path(project, ref, format: :json))
- end
- end
end
it 'assigns url' do
diff --git a/spec/requests/projects/noteable_notes_spec.rb b/spec/requests/projects/noteable_notes_spec.rb
index 5699bf17b80..55540447da0 100644
--- a/spec/requests/projects/noteable_notes_spec.rb
+++ b/spec/requests/projects/noteable_notes_spec.rb
@@ -36,5 +36,41 @@ RSpec.describe 'Project noteable notes', feature_category: :team_planning do
expect(response).to have_gitlab_http_status(:ok)
expect(response_etag).to eq(stored_etag)
end
+
+ it "instruments cache hits correctly" do
+ etag_store.touch(notes_path)
+
+ expect(Gitlab::Metrics::RailsSlis.request_apdex).to(
+ receive(:increment).with(
+ labels: {
+ request_urgency: :medium,
+ feature_category: "team_planning",
+ endpoint_id: "Projects::NotesController#index"
+ },
+ success: be_in([true, false])
+ )
+ )
+ allow(ActiveSupport::Notifications).to receive(:instrument).and_call_original
+
+ expect(ActiveSupport::Notifications).to(
+ receive(:instrument).with(
+ 'process_action.action_controller',
+ a_hash_including(
+ {
+ request_urgency: :medium,
+ target_duration_s: 0.5,
+ metadata: a_hash_including({
+ 'meta.feature_category' => 'team_planning',
+ 'meta.caller_id' => "Projects::NotesController#index"
+ })
+ }
+ )
+ )
+ )
+
+ get notes_path, headers: { "if-none-match": stored_etag }
+
+ expect(response).to have_gitlab_http_status(:not_modified)
+ end
end
end
diff --git a/spec/requests/projects/pipelines_controller_spec.rb b/spec/requests/projects/pipelines_controller_spec.rb
index 7f185ade339..73e002b63b1 100644
--- a/spec/requests/projects/pipelines_controller_spec.rb
+++ b/spec/requests/projects/pipelines_controller_spec.rb
@@ -19,6 +19,32 @@ RSpec.describe Projects::PipelinesController, feature_category: :continuous_inte
login_as(user)
end
+ describe "GET index.json" do
+ it 'does not execute N+1 queries' do
+ get_pipelines_index
+
+ control_count = ActiveRecord::QueryRecorder.new do
+ get_pipelines_index
+ end.count
+
+ %w[pending running success failed canceled].each do |status|
+ create(:ci_pipeline, project: project, status: status)
+ end
+
+ # There appears to be one extra query for Pipelines#has_warnings? for some reason
+ expect { get_pipelines_index }.not_to exceed_query_limit(control_count + 1)
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['pipelines'].count).to eq 6
+ end
+
+ def get_pipelines_index
+ get namespace_project_pipelines_path(
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ format: :json)
+ end
+ end
+
describe "GET stages.json" do
it 'does not execute N+1 queries' do
request_build_stage
diff --git a/spec/requests/projects/releases_controller_spec.rb b/spec/requests/projects/releases_controller_spec.rb
index d331142583d..42fd55b5a43 100644
--- a/spec/requests/projects/releases_controller_spec.rb
+++ b/spec/requests/projects/releases_controller_spec.rb
@@ -8,17 +8,20 @@ RSpec.describe 'Projects::ReleasesController', feature_category: :release_orches
before do
project.add_developer(user)
- login_as(user)
end
# Added as a request spec because of https://gitlab.com/gitlab-org/gitlab/-/issues/232386
describe 'GET #downloads' do
- context 'filepath redirection' do
- let_it_be(:release) { create(:release, project: project, tag: 'v11.9.0-rc2' ) }
- let!(:link) { create(:release_link, release: release, name: 'linux-amd64 binaries', filepath: filepath, url: 'https://aws.example.com/s3/project/bin/hello-darwin-amd64') }
- let_it_be(:url) { "#{project_releases_path(project)}/#{release.tag}/downloads/bin/darwin-amd64" }
+ let_it_be(:release) { create(:release, project: project, tag: 'v11.9.0-rc2' ) }
+ let!(:link) { create(:release_link, release: release, name: 'linux-amd64 binaries', filepath: filepath, url: 'https://aws.example.com/s3/project/bin/hello-darwin-amd64') }
+ let_it_be(:url) { "#{project_releases_path(project)}/#{release.tag}/downloads/bin/darwin-amd64" }
- let(:subject) { get url }
+ let(:subject) { get url }
+
+ context 'filepath redirection' do
+ before do
+ login_as(user)
+ end
context 'valid filepath' do
let(:filepath) { '/bin/darwin-amd64' }
@@ -47,14 +50,29 @@ RSpec.describe 'Projects::ReleasesController', feature_category: :release_orches
end
end
- context 'invalid filepath' do
- let(:invalid_filepath) { 'bin/darwin-amd64' }
+ context 'sessionless download authentication' do
+ let(:personal_access_token) { create(:personal_access_token, user: user) }
+ let(:filepath) { '/bin/darwin-amd64' }
+
+ subject { get url, params: { private_token: personal_access_token.token } }
- let(:subject) { create(:release_link, name: 'linux-amd64 binaries', filepath: invalid_filepath, url: 'https://aws.example.com/s3/project/bin/hello-darwin-amd64') }
+ it 'will allow sessionless users to download the file' do
+ subject
- it 'cannot create an invalid filepath' do
- expect { subject }.to raise_error(ActiveRecord::RecordInvalid)
+ expect(controller.current_user).to eq(user)
+ expect(response).to have_gitlab_http_status(:redirect)
+ expect(response).to redirect_to(link.url)
end
end
end
+
+ context 'invalid filepath' do
+ let(:invalid_filepath) { 'bin/darwin-amd64' }
+
+ let(:subject) { create(:release_link, name: 'linux-amd64 binaries', filepath: invalid_filepath, url: 'https://aws.example.com/s3/project/bin/hello-darwin-amd64') }
+
+ it 'cannot create an invalid filepath' do
+ expect { subject }.to raise_error(ActiveRecord::RecordInvalid)
+ end
+ end
end