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:
Diffstat (limited to 'spec/lib/api')
-rw-r--r--spec/lib/api/ci/helpers/runner_spec.rb34
-rw-r--r--spec/lib/api/entities/merge_request_basic_spec.rb2
-rw-r--r--spec/lib/api/entities/merge_request_diff_spec.rb44
-rw-r--r--spec/lib/api/entities/ml/mlflow/get_run_spec.rb63
-rw-r--r--spec/lib/api/entities/ml/mlflow/run_info_spec.rb2
-rw-r--r--spec/lib/api/entities/ml/mlflow/run_spec.rb20
-rw-r--r--spec/lib/api/entities/ml/mlflow/search_runs_spec.rb37
-rw-r--r--spec/lib/api/entities/project_spec.rb2
-rw-r--r--spec/lib/api/helpers/packages_helpers_spec.rb4
-rw-r--r--spec/lib/api/helpers_spec.rb222
-rw-r--r--spec/lib/api/ml/mlflow/api_helpers_spec.rb24
11 files changed, 422 insertions, 32 deletions
diff --git a/spec/lib/api/ci/helpers/runner_spec.rb b/spec/lib/api/ci/helpers/runner_spec.rb
index 62b79c77b4a..70504a58af3 100644
--- a/spec/lib/api/ci/helpers/runner_spec.rb
+++ b/spec/lib/api/ci/helpers/runner_spec.rb
@@ -3,10 +3,18 @@
require 'spec_helper'
RSpec.describe API::Ci::Helpers::Runner do
- let(:helper) { Class.new { include API::Ci::Helpers::Runner }.new }
+ let(:helper) do
+ Class.new do
+ include API::Ci::Helpers::Runner
+ include Gitlab::RackLoadBalancingHelpers
+ end.new
+ end
+
+ let(:env_hash) { {} }
+ let(:request) { instance_double(Rack::Request, env: env_hash) }
before do
- allow(helper).to receive(:env).and_return({})
+ allow(helper).to receive(:request).and_return(request)
end
describe '#current_job', feature_category: :continuous_integration do
@@ -16,17 +24,22 @@ RSpec.describe API::Ci::Helpers::Runner do
allow(helper).to receive(:params).and_return(id: build.id)
expect(Ci::Build.sticking)
- .to receive(:stick_or_unstick_request)
- .with({}, :build, build.id)
+ .to receive(:find_caught_up_replica)
+ .with(:build, build.id)
helper.current_job
+
+ stick_object = env_hash[::Gitlab::Database::LoadBalancing::RackMiddleware::STICK_OBJECT].first
+ expect(stick_object[0]).to eq(Ci::Build.sticking)
+ expect(stick_object[1]).to eq(:build)
+ expect(stick_object[2]).to eq(build.id)
end
it 'does not handle sticking if no build ID was specified' do
allow(helper).to receive(:params).and_return({})
expect(Ci::Build.sticking)
- .not_to receive(:stick_or_unstick_request)
+ .not_to receive(:find_caught_up_replica)
helper.current_job
end
@@ -45,17 +58,22 @@ RSpec.describe API::Ci::Helpers::Runner do
allow(helper).to receive(:params).and_return(token: runner.token)
expect(Ci::Runner.sticking)
- .to receive(:stick_or_unstick_request)
- .with({}, :runner, runner.token)
+ .to receive(:find_caught_up_replica)
+ .with(:runner, runner.token)
helper.current_runner
+
+ stick_object = env_hash[::Gitlab::Database::LoadBalancing::RackMiddleware::STICK_OBJECT].first
+ expect(stick_object[0]).to eq(Ci::Runner.sticking)
+ expect(stick_object[1]).to eq(:runner)
+ expect(stick_object[2]).to eq(runner.token)
end
it 'does not handle sticking if no token was specified' do
allow(helper).to receive(:params).and_return({})
expect(Ci::Runner.sticking)
- .not_to receive(:stick_or_unstick_request)
+ .not_to receive(:find_caught_up_replica)
helper.current_runner
end
diff --git a/spec/lib/api/entities/merge_request_basic_spec.rb b/spec/lib/api/entities/merge_request_basic_spec.rb
index 89e19f8529e..0cf0a57fa87 100644
--- a/spec/lib/api/entities/merge_request_basic_spec.rb
+++ b/spec/lib/api/entities/merge_request_basic_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::API::Entities::MergeRequestBasic do
+RSpec.describe ::API::Entities::MergeRequestBasic, feature_category: :code_review_workflow do
let_it_be(:user) { create(:user) }
let_it_be(:merge_request) { create(:merge_request) }
let_it_be(:labels) { create_list(:label, 3) }
diff --git a/spec/lib/api/entities/merge_request_diff_spec.rb b/spec/lib/api/entities/merge_request_diff_spec.rb
new file mode 100644
index 00000000000..a6927914316
--- /dev/null
+++ b/spec/lib/api/entities/merge_request_diff_spec.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::API::Entities::MergeRequestDiff, feature_category: :code_review_workflow do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:merge_request) { create(:merge_request) }
+ let_it_be(:project) { merge_request.target_project }
+ let_it_be(:entity) { described_class.new(merge_request.merge_request_diffs.first) }
+
+ before do
+ merge_request.merge_request_diffs.create!(head_commit_sha: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9')
+ merge_request.merge_request_diffs.create!(head_commit_sha: '5937ac0a7beb003549fc5fd26fc247adbce4a52e')
+ end
+
+ subject(:json) { entity.as_json }
+
+ it "includes expected fields" do
+ expected_fields = %i[
+ id head_commit_sha base_commit_sha start_commit_sha created_at
+ merge_request_id state real_size patch_id_sha
+ ]
+
+ is_expected.to include(*expected_fields)
+ end
+
+ it "returns expected data" do
+ merge_request_diff = merge_request.merge_request_diffs.first
+
+ expect(entity.as_json).to eq(
+ {
+ id: merge_request_diff.id,
+ head_commit_sha: merge_request_diff.head_commit_sha,
+ base_commit_sha: merge_request_diff.base_commit_sha,
+ start_commit_sha: merge_request_diff.start_commit_sha,
+ created_at: merge_request_diff.created_at,
+ merge_request_id: merge_request.id,
+ state: merge_request_diff.state,
+ real_size: merge_request_diff.real_size,
+ patch_id_sha: merge_request_diff.patch_id_sha
+ }
+ )
+ end
+end
diff --git a/spec/lib/api/entities/ml/mlflow/get_run_spec.rb b/spec/lib/api/entities/ml/mlflow/get_run_spec.rb
new file mode 100644
index 00000000000..513ecdeee3c
--- /dev/null
+++ b/spec/lib/api/entities/ml/mlflow/get_run_spec.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe API::Entities::Ml::Mlflow::GetRun, feature_category: :mlops do
+ let_it_be(:candidate) { build(:ml_candidates, :with_metrics_and_params) }
+
+ subject { described_class.new(candidate).as_json }
+
+ it 'has run key' do
+ expect(subject).to have_key(:run)
+ end
+
+ it 'has the id' do
+ expect(subject.dig(:run, :info, :run_id)).to eq(candidate.eid.to_s)
+ end
+
+ it 'presents the metrics' do
+ expect(subject.dig(:run, :data, :metrics).size).to eq(candidate.metrics.size)
+ end
+
+ it 'presents metrics correctly' do
+ presented_metric = subject.dig(:run, :data, :metrics)[0]
+ metric = candidate.metrics[0]
+
+ expect(presented_metric[:key]).to eq(metric.name)
+ expect(presented_metric[:value]).to eq(metric.value)
+ expect(presented_metric[:timestamp]).to eq(metric.tracked_at)
+ expect(presented_metric[:step]).to eq(metric.step)
+ end
+
+ it 'presents the params' do
+ expect(subject.dig(:run, :data, :params).size).to eq(candidate.params.size)
+ end
+
+ it 'presents params correctly' do
+ presented_param = subject.dig(:run, :data, :params)[0]
+ param = candidate.params[0]
+
+ expect(presented_param[:key]).to eq(param.name)
+ expect(presented_param[:value]).to eq(param.value)
+ end
+
+ context 'when candidate has no metrics' do
+ before do
+ allow(candidate).to receive(:metrics).and_return([])
+ end
+
+ it 'returns empty data' do
+ expect(subject.dig(:run, :data, :metrics)).to be_empty
+ end
+ end
+
+ context 'when candidate has no params' do
+ before do
+ allow(candidate).to receive(:params).and_return([])
+ end
+
+ it 'data is empty' do
+ expect(subject.dig(:run, :data, :params)).to be_empty
+ end
+ end
+end
diff --git a/spec/lib/api/entities/ml/mlflow/run_info_spec.rb b/spec/lib/api/entities/ml/mlflow/run_info_spec.rb
index 28fef16a532..1664d9f18d2 100644
--- a/spec/lib/api/entities/ml/mlflow/run_info_spec.rb
+++ b/spec/lib/api/entities/ml/mlflow/run_info_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe API::Entities::Ml::Mlflow::RunInfo, feature_category: :mlops do
- let_it_be(:candidate) { create(:ml_candidates) }
+ let_it_be(:candidate) { build(:ml_candidates) }
subject { described_class.new(candidate, packages_url: 'http://example.com').as_json }
diff --git a/spec/lib/api/entities/ml/mlflow/run_spec.rb b/spec/lib/api/entities/ml/mlflow/run_spec.rb
index a57f70f788b..58148212a7b 100644
--- a/spec/lib/api/entities/ml/mlflow/run_spec.rb
+++ b/spec/lib/api/entities/ml/mlflow/run_spec.rb
@@ -3,24 +3,20 @@
require 'spec_helper'
RSpec.describe API::Entities::Ml::Mlflow::Run do
- let_it_be(:candidate) { create(:ml_candidates, :with_metrics_and_params) }
+ let_it_be(:candidate) { build(:ml_candidates, :with_metrics_and_params) }
subject { described_class.new(candidate).as_json }
- it 'has run key' do
- expect(subject).to have_key(:run)
- end
-
it 'has the id' do
- expect(subject.dig(:run, :info, :run_id)).to eq(candidate.eid.to_s)
+ expect(subject.dig(:info, :run_id)).to eq(candidate.eid.to_s)
end
it 'presents the metrics' do
- expect(subject.dig(:run, :data, :metrics).size).to eq(candidate.metrics.size)
+ expect(subject.dig(:data, :metrics).size).to eq(candidate.metrics.size)
end
it 'presents metrics correctly' do
- presented_metric = subject.dig(:run, :data, :metrics)[0]
+ presented_metric = subject.dig(:data, :metrics)[0]
metric = candidate.metrics[0]
expect(presented_metric[:key]).to eq(metric.name)
@@ -30,11 +26,11 @@ RSpec.describe API::Entities::Ml::Mlflow::Run do
end
it 'presents the params' do
- expect(subject.dig(:run, :data, :params).size).to eq(candidate.params.size)
+ expect(subject.dig(:data, :params).size).to eq(candidate.params.size)
end
it 'presents params correctly' do
- presented_param = subject.dig(:run, :data, :params)[0]
+ presented_param = subject.dig(:data, :params)[0]
param = candidate.params[0]
expect(presented_param[:key]).to eq(param.name)
@@ -47,7 +43,7 @@ RSpec.describe API::Entities::Ml::Mlflow::Run do
end
it 'returns empty data' do
- expect(subject.dig(:run, :data, :metrics)).to be_empty
+ expect(subject.dig(:data, :metrics)).to be_empty
end
end
@@ -57,7 +53,7 @@ RSpec.describe API::Entities::Ml::Mlflow::Run do
end
it 'data is empty' do
- expect(subject.dig(:run, :data, :params)).to be_empty
+ expect(subject.dig(:data, :params)).to be_empty
end
end
end
diff --git a/spec/lib/api/entities/ml/mlflow/search_runs_spec.rb b/spec/lib/api/entities/ml/mlflow/search_runs_spec.rb
new file mode 100644
index 00000000000..6ed59d454fa
--- /dev/null
+++ b/spec/lib/api/entities/ml/mlflow/search_runs_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe API::Entities::Ml::Mlflow::SearchRuns, feature_category: :mlops do
+ let_it_be(:candidates) { [build_stubbed(:ml_candidates, :with_metrics_and_params), build_stubbed(:ml_candidates)] }
+
+ let(:next_page_token) { 'abcdef' }
+
+ subject { described_class.new({ candidates: candidates, next_page_token: next_page_token }).as_json }
+
+ it 'presents the candidates', :aggregate_failures do
+ expect(subject[:runs].size).to eq(2)
+ expect(subject.dig(:runs, 0, :info, :run_id)).to eq(candidates[0].eid.to_s)
+ expect(subject.dig(:runs, 1, :info, :run_id)).to eq(candidates[1].eid.to_s)
+ end
+
+ it 'presents metrics', :aggregate_failures do
+ expect(subject.dig(:runs, 0, :data, :metrics).size).to eq(candidates[0].metrics.size)
+ expect(subject.dig(:runs, 1, :data, :metrics).size).to eq(0)
+
+ presented_metric = subject.dig(:runs, 0, :data, :metrics, 0, :key)
+ metric = candidates[0].metrics[0].name
+
+ expect(presented_metric).to eq(metric)
+ end
+
+ it 'presents params', :aggregate_failures do
+ expect(subject.dig(:runs, 0, :data, :params).size).to eq(candidates[0].params.size)
+ expect(subject.dig(:runs, 1, :data, :params).size).to eq(0)
+
+ presented_param = subject.dig(:runs, 0, :data, :params, 0, :key)
+ param = candidates[0].params[0].name
+
+ expect(presented_param).to eq(param)
+ end
+end
diff --git a/spec/lib/api/entities/project_spec.rb b/spec/lib/api/entities/project_spec.rb
index 5d18b93228f..2c2cabba5e9 100644
--- a/spec/lib/api/entities/project_spec.rb
+++ b/spec/lib/api/entities/project_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe ::API::Entities::Project do
end
end
- describe '.service_desk_address' do
+ describe '.service_desk_address', feature_category: :service_desk do
before do
allow(project).to receive(:service_desk_enabled?).and_return(true)
end
diff --git a/spec/lib/api/helpers/packages_helpers_spec.rb b/spec/lib/api/helpers/packages_helpers_spec.rb
index 6ba4396c396..bb7b9d688ea 100644
--- a/spec/lib/api/helpers/packages_helpers_spec.rb
+++ b/spec/lib/api/helpers/packages_helpers_spec.rb
@@ -292,7 +292,7 @@ RSpec.describe API::Helpers::PackagesHelpers, feature_category: :package_registr
let(:label) { 'counts.package_events_i_package_push_package_by_deploy_token' }
let(:property) { 'i_package_push_package_by_deploy_token' }
let(:service_ping_context) do
- [Gitlab::Tracking::ServicePingContext.new(data_source: :redis, key_path: 'counts.package_events_i_package_push_package_by_deploy_token').to_h]
+ [Gitlab::Usage::MetricDefinition.context_for('counts.package_events_i_package_push_package_by_deploy_token').to_h]
end
it 'logs a snowplow event' do
@@ -320,7 +320,7 @@ RSpec.describe API::Helpers::PackagesHelpers, feature_category: :package_registr
let(:label) { 'counts.package_events_i_package_pull_package_by_guest' }
let(:property) { 'i_package_pull_package_by_guest' }
let(:service_ping_context) do
- [Gitlab::Tracking::ServicePingContext.new(data_source: :redis, key_path: 'counts.package_events_i_package_pull_package_by_guest').to_h]
+ [Gitlab::Usage::MetricDefinition.context_for('counts.package_events_i_package_pull_package_by_guest').to_h]
end
it 'logs a snowplow event' do
diff --git a/spec/lib/api/helpers_spec.rb b/spec/lib/api/helpers_spec.rb
index 667ee72f821..dd62343890e 100644
--- a/spec/lib/api/helpers_spec.rb
+++ b/spec/lib/api/helpers_spec.rb
@@ -11,7 +11,6 @@ RSpec.describe API::Helpers, feature_category: :shared do
include Rack::Test::Methods
let(:user) { build(:user, id: 42) }
- let(:request) { instance_double(Rack::Request) }
let(:helper) do
Class.new(Grape::API::Instance) do
helpers API::APIGuard::HelperMethods
@@ -36,18 +35,23 @@ RSpec.describe API::Helpers, feature_category: :shared do
allow_any_instance_of(described_class).to receive(:initial_current_user).and_return(user)
expect(ApplicationRecord.sticking)
- .to receive(:stick_or_unstick_request).with(any_args, :user, 42)
+ .to receive(:find_caught_up_replica).with(:user, 42)
get 'user'
expect(Gitlab::Json.parse(last_response.body)).to eq({ 'id' => user.id })
+
+ stick_object = last_request.env[::Gitlab::Database::LoadBalancing::RackMiddleware::STICK_OBJECT].first
+ expect(stick_object[0]).to eq(User.sticking)
+ expect(stick_object[1]).to eq(:user)
+ expect(stick_object[2]).to eq(42)
end
it 'does not handle sticking if no user could be found' do
allow_any_instance_of(described_class).to receive(:initial_current_user).and_return(nil)
expect(ApplicationRecord.sticking)
- .not_to receive(:stick_or_unstick_request)
+ .not_to receive(:find_caught_up_replica)
get 'user'
@@ -243,6 +247,165 @@ RSpec.describe API::Helpers, feature_category: :shared do
end
end
+ describe '#find_pipeline' do
+ let(:pipeline) { create(:ci_pipeline) }
+
+ shared_examples 'pipeline finder' do
+ context 'when pipeline exists' do
+ it 'returns requested pipeline' do
+ expect(helper.find_pipeline(existing_id)).to eq(pipeline)
+ end
+ end
+
+ context 'when pipeline does not exists' do
+ it 'returns nil' do
+ expect(helper.find_pipeline(non_existing_id)).to be_nil
+ end
+ end
+
+ context 'when pipeline id is not provided' do
+ it 'returns nil' do
+ expect(helper.find_pipeline(nil)).to be_nil
+ end
+ end
+ end
+
+ context 'when ID is used as an argument' do
+ let(:existing_id) { pipeline.id }
+ let(:non_existing_id) { non_existing_record_id }
+
+ it_behaves_like 'pipeline finder'
+ end
+
+ context 'when string ID is used as an argument' do
+ let(:existing_id) { pipeline.id.to_s }
+ let(:non_existing_id) { non_existing_record_id }
+
+ it_behaves_like 'pipeline finder'
+ end
+
+ context 'when ID is a negative number' do
+ let(:existing_id) { pipeline.id }
+ let(:non_existing_id) { -1 }
+
+ it_behaves_like 'pipeline finder'
+ end
+ end
+
+ describe '#find_pipeline!' do
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
+ let_it_be(:user) { create(:user) }
+
+ shared_examples 'private project without access' do
+ before do
+ project.update_column(:visibility_level, Gitlab::VisibilityLevel.level_value('private'))
+ allow(helper).to receive(:authenticate_non_public?).and_return(false)
+ end
+
+ it 'returns not found' do
+ expect(helper).to receive(:not_found!)
+
+ helper.find_pipeline!(pipeline.id)
+ end
+ end
+
+ context 'when user is authenticated' do
+ before do
+ allow(helper).to receive(:current_user).and_return(user)
+ allow(helper).to receive(:initial_current_user).and_return(user)
+ end
+
+ context 'public project' do
+ it 'returns requested pipeline' do
+ expect(helper.find_pipeline!(pipeline.id)).to eq(pipeline)
+ end
+ end
+
+ context 'private project' do
+ it_behaves_like 'private project without access'
+
+ context 'without read pipeline permission' do
+ before do
+ allow(helper).to receive(:can?).with(user, :read_pipeline, pipeline).and_return(false)
+ end
+
+ it_behaves_like 'private project without access'
+ end
+ end
+
+ context 'with read pipeline permission' do
+ before do
+ allow(helper).to receive(:can?).with(user, :read_pipeline, pipeline).and_return(true)
+ end
+
+ it 'returns requested pipeline' do
+ expect(helper.find_pipeline!(pipeline.id)).to eq(pipeline)
+ end
+ end
+ end
+
+ context 'when user is not authenticated' do
+ before do
+ allow(helper).to receive(:current_user).and_return(nil)
+ allow(helper).to receive(:initial_current_user).and_return(nil)
+ end
+
+ context 'public project' do
+ it 'returns requested pipeline' do
+ expect(helper.find_pipeline!(pipeline.id)).to eq(pipeline)
+ end
+ end
+
+ context 'private project' do
+ it_behaves_like 'private project without access'
+ end
+ end
+
+ context 'support for IDs and paths as argument' do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
+
+ let(:user) { project.first_owner }
+
+ before do
+ allow(helper).to receive(:current_user).and_return(user)
+ allow(helper).to receive(:authorized_project_scope?).and_return(true)
+ allow(helper).to receive(:job_token_authentication?).and_return(false)
+ allow(helper).to receive(:authenticate_non_public?).and_return(false)
+ end
+
+ shared_examples 'pipeline finder' do
+ context 'when pipeline exists' do
+ it 'returns requested pipeline' do
+ expect(helper.find_pipeline!(existing_id)).to eq(pipeline)
+ end
+
+ it 'returns nil' do
+ expect(helper).to receive(:render_api_error!).with('404 Pipeline Not Found', 404)
+ expect(helper.find_pipeline!(non_existing_id)).to be_nil
+ end
+ end
+ end
+
+ context 'when ID is used as an argument' do
+ context 'when pipeline id is an integer' do
+ let(:existing_id) { pipeline.id }
+ let(:non_existing_id) { non_existing_record_id }
+
+ it_behaves_like 'pipeline finder'
+ end
+
+ context 'when pipeline id is a string' do
+ let(:existing_id) { pipeline.id.to_s }
+ let(:non_existing_id) { "non_existing_record_id" }
+
+ it_behaves_like 'pipeline finder'
+ end
+ end
+ end
+ end
+
describe '#find_group!' do
let_it_be(:group) { create(:group, :public) }
let_it_be(:user) { create(:user) }
@@ -628,10 +791,12 @@ RSpec.describe API::Helpers, feature_category: :shared do
end
it 'logs an exception for unknown event' do
- expect(Gitlab::AppLogger).to receive(:warn).with(
- "Internal Event tracking event failed for event: #{unknown_event}, message: Unknown event: #{unknown_event}"
- )
-
+ expect(Gitlab::InternalEvents).to receive(:track_event).and_raise(Gitlab::InternalEvents::UnknownEventError, "Unknown event: #{unknown_event}")
+ expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception)
+ .with(
+ instance_of(Gitlab::InternalEvents::UnknownEventError),
+ event_name: unknown_event
+ )
helper.track_event(unknown_event, user_id: user_id, namespace_id: namespace_id, project_id: project_id)
end
@@ -1072,4 +1237,47 @@ RSpec.describe API::Helpers, feature_category: :shared do
it_behaves_like 'authorized'
end
end
+
+ describe "attributes_for_keys" do
+ let(:hash) do
+ {
+ existing_key_with_present_value: 'actual value',
+ existing_key_with_nil_value: nil,
+ existing_key_with_false_value: false
+ }
+ end
+
+ let(:parameters) { ::ActionController::Parameters.new(hash) }
+ let(:symbol_keys) do
+ %i[
+ existing_key_with_present_value
+ existing_key_with_nil_value
+ existing_key_with_false_value
+ non_existing_key
+ ]
+ end
+
+ let(:string_keys) { symbol_keys.map(&:to_s) }
+ let(:filtered_attrs) do
+ {
+ 'existing_key_with_present_value' => 'actual value',
+ 'existing_key_with_false_value' => false
+ }
+ end
+
+ let(:empty_attrs) { {} }
+
+ where(:params, :keys, :attrs_result) do
+ ref(:hash) | ref(:symbol_keys) | ref(:filtered_attrs)
+ ref(:hash) | ref(:string_keys) | ref(:empty_attrs)
+ ref(:parameters) | ref(:symbol_keys) | ref(:filtered_attrs)
+ ref(:parameters) | ref(:string_keys) | ref(:filtered_attrs)
+ end
+
+ with_them do
+ it 'returns the values for given keys' do
+ expect(helper.attributes_for_keys(keys, params)).to eq(attrs_result)
+ end
+ end
+ end
end
diff --git a/spec/lib/api/ml/mlflow/api_helpers_spec.rb b/spec/lib/api/ml/mlflow/api_helpers_spec.rb
index 4f6a37c66c4..757a73ed612 100644
--- a/spec/lib/api/ml/mlflow/api_helpers_spec.rb
+++ b/spec/lib/api/ml/mlflow/api_helpers_spec.rb
@@ -37,4 +37,28 @@ RSpec.describe API::Ml::Mlflow::ApiHelpers, feature_category: :mlops do
it { is_expected.to eql("http://localhost/gitlab/root/api/v4/projects/#{user_project.id}/packages/generic") }
end
end
+
+ describe '#candidates_order_params' do
+ using RSpec::Parameterized::TableSyntax
+
+ subject { candidates_order_params(params) }
+
+ where(:input, :order_by, :order_by_type, :sort) do
+ '' | nil | nil | nil
+ 'created_at' | 'created_at' | 'column' | nil
+ 'created_at ASC' | 'created_at' | 'column' | 'ASC'
+ 'metrics.something' | 'something' | 'metric' | nil
+ 'metrics.something asc' | 'something' | 'metric' | 'asc'
+ 'metrics.something.blah asc' | 'something' | 'metric' | 'asc'
+ 'params.something ASC' | nil | nil | 'ASC'
+ 'metadata.something ASC' | nil | nil | 'ASC'
+ end
+ with_them do
+ let(:params) { { order_by: input } }
+
+ it 'is correct' do
+ is_expected.to include({ order_by: order_by, order_by_type: order_by_type, sort: sort })
+ end
+ end
+ end
end