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/requests/api/ml/mlflow_spec.rb')
-rw-r--r--spec/requests/api/ml/mlflow_spec.rb135
1 files changed, 124 insertions, 11 deletions
diff --git a/spec/requests/api/ml/mlflow_spec.rb b/spec/requests/api/ml/mlflow_spec.rb
index 9448f009742..c1ed7d56ba4 100644
--- a/spec/requests/api/ml/mlflow_spec.rb
+++ b/spec/requests/api/ml/mlflow_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require 'mime/types'
-RSpec.describe API::Ml::Mlflow do
+RSpec.describe API::Ml::Mlflow, feature_category: :mlops do
include SessionHelpers
include ApiHelpers
include HttpBasicAuthHelpers
@@ -12,12 +12,13 @@ RSpec.describe API::Ml::Mlflow do
let_it_be(:developer) { create(:user).tap { |u| project.add_developer(u) } }
let_it_be(:another_project) { build(:project).tap { |p| p.add_developer(developer) } }
let_it_be(:experiment) do
- create(:ml_experiments, user: project.creator, project: project)
+ create(:ml_experiments, :with_metadata, project: project)
end
let_it_be(:candidate) do
create(:ml_candidates,
- :with_metrics_and_params, user: experiment.user, start_time: 1234, experiment: experiment)
+ :with_metrics_and_params, :with_metadata,
+ user: experiment.user, start_time: 1234, experiment: experiment)
end
let_it_be(:tokens) do
@@ -151,7 +152,17 @@ RSpec.describe API::Ml::Mlflow do
'experiment_id' => experiment_iid,
'name' => experiment.name,
'lifecycle_stage' => 'active',
- 'artifact_location' => 'not_implemented'
+ 'artifact_location' => 'not_implemented',
+ 'tags' => [
+ {
+ 'key' => experiment.metadata[0].name,
+ 'value' => experiment.metadata[0].value
+ },
+ {
+ 'key' => experiment.metadata[1].name,
+ 'value' => experiment.metadata[1].value
+ }
+ ]
}
})
end
@@ -187,7 +198,17 @@ RSpec.describe API::Ml::Mlflow do
'experiment_id' => experiment.iid.to_s,
'name' => experiment.name,
'lifecycle_stage' => 'active',
- 'artifact_location' => 'not_implemented'
+ 'artifact_location' => 'not_implemented',
+ 'tags' => [
+ {
+ 'key' => experiment.metadata[0].name,
+ 'value' => experiment.metadata[0].value
+ },
+ {
+ 'key' => experiment.metadata[1].name,
+ 'value' => experiment.metadata[1].value
+ }
+ ]
]
})
end
@@ -220,7 +241,17 @@ RSpec.describe API::Ml::Mlflow do
'experiment_id' => experiment.iid.to_s,
'name' => experiment_name,
'lifecycle_stage' => 'active',
- 'artifact_location' => 'not_implemented'
+ 'artifact_location' => 'not_implemented',
+ 'tags' => [
+ {
+ 'key' => experiment.metadata[0].name,
+ 'value' => experiment.metadata[0].value
+ },
+ {
+ 'key' => experiment.metadata[1].name,
+ 'value' => experiment.metadata[1].value
+ }
+ ]
}
})
end
@@ -284,10 +315,44 @@ RSpec.describe API::Ml::Mlflow do
end
end
+ describe 'POST /projects/:id/ml/mlflow/api/2.0/mlflow/experiments/set-experiment-tag' do
+ let(:route) { "/projects/#{project_id}/ml/mlflow/api/2.0/mlflow/experiments/set-experiment-tag" }
+ let(:default_params) { { experiment_id: experiment.iid.to_s, key: 'some_key', value: 'value' } }
+ let(:params) { default_params }
+ let(:request) { post api(route), params: params, headers: headers }
+
+ it 'logs the tag', :aggregate_failures do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_empty
+ expect(experiment.reload.metadata.map(&:name)).to include('some_key')
+ end
+
+ describe 'Error Cases' do
+ context 'when tag was already set' do
+ let(:params) { default_params.merge(key: experiment.metadata[0].name) }
+
+ it_behaves_like 'Bad Request'
+ end
+
+ it_behaves_like 'shared error cases'
+ it_behaves_like 'Requires api scope'
+ it_behaves_like 'Bad Request on missing required', [:key, :value]
+ end
+ end
+
describe 'Runs' do
describe 'POST /projects/:id/ml/mlflow/api/2.0/mlflow/runs/create' do
let(:route) { "/projects/#{project_id}/ml/mlflow/api/2.0/mlflow/runs/create" }
- let(:params) { { experiment_id: experiment.iid.to_s, start_time: Time.now.to_i } }
+ let(:params) do
+ {
+ experiment_id: experiment.iid.to_s,
+ start_time: Time.now.to_i,
+ tags: [
+ { key: 'hello', value: 'world' }
+ ]
+ }
+ end
+
let(:request) { post api(route), params: params, headers: headers }
it 'creates the run', :aggregate_failures do
@@ -295,14 +360,18 @@ RSpec.describe API::Ml::Mlflow do
'experiment_id' => params[:experiment_id],
'user_id' => current_user.id.to_s,
'start_time' => params[:start_time],
- 'status' => "RUNNING",
- 'lifecycle_stage' => "active"
+ 'status' => 'RUNNING',
+ 'lifecycle_stage' => 'active'
}
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('ml/run')
expect(json_response['run']).to include('info' => hash_including(**expected_properties),
- 'data' => { 'metrics' => [], 'params' => [] })
+ 'data' => {
+ 'metrics' => [],
+ 'params' => [],
+ 'tags' => [{ 'key' => 'hello', 'value' => 'world' }]
+ })
end
describe 'Error States' do
@@ -355,6 +424,10 @@ RSpec.describe API::Ml::Mlflow do
'params' => [
{ 'key' => candidate.params[0].name, 'value' => candidate.params[0].value },
{ 'key' => candidate.params[1].name, 'value' => candidate.params[1].value }
+ ],
+ 'tags' => [
+ { 'key' => 'metadata_1', 'value' => 'value1' },
+ { 'key' => 'metadata_2', 'value' => 'value2' }
]
})
end
@@ -454,6 +527,31 @@ RSpec.describe API::Ml::Mlflow do
end
end
+ describe 'POST /projects/:id/ml/mlflow/api/2.0/mlflow/runs/set-tag' do
+ let(:route) { "/projects/#{project_id}/ml/mlflow/api/2.0/mlflow/runs/set-tag" }
+ let(:default_params) { { run_id: candidate.iid.to_s, key: 'some_key', value: 'value' } }
+ let(:request) { post api(route), params: params, headers: headers }
+
+ it 'logs the tag', :aggregate_failures do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_empty
+ expect(candidate.reload.metadata.map(&:name)).to include('some_key')
+ end
+
+ describe 'Error Cases' do
+ context 'when tag was already logged' do
+ let(:params) { default_params.tap { |p| p[:key] = candidate.metadata[0].name } }
+
+ it_behaves_like 'Bad Request'
+ end
+
+ it_behaves_like 'shared error cases'
+ it_behaves_like 'Requires api scope'
+ it_behaves_like 'run_id param error cases'
+ it_behaves_like 'Bad Request on missing required', [:key, :value]
+ end
+ end
+
describe 'POST /projects/:id/ml/mlflow/api/2.0/mlflow/runs/log-batch' do
let(:candidate2) do
create(:ml_candidates, user: experiment.user, start_time: 1234, experiment: experiment)
@@ -467,7 +565,8 @@ RSpec.describe API::Ml::Mlflow do
{ key: 'mae', value: 2.5, timestamp: 1552550804 },
{ key: 'rmse', value: 2.7, timestamp: 1552550804 }
],
- params: [{ key: 'model_class', value: 'LogisticRegression' }]
+ params: [{ key: 'model_class', value: 'LogisticRegression' }],
+ tags: [{ key: 'tag1', value: 'tag.value.1' }]
}
end
@@ -477,6 +576,7 @@ RSpec.describe API::Ml::Mlflow do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_empty
expect(candidate2.params.size).to eq(1)
+ expect(candidate2.metadata.size).to eq(1)
expect(candidate2.metrics.size).to eq(2)
end
@@ -493,6 +593,19 @@ RSpec.describe API::Ml::Mlflow do
end
end
+ context 'when tag was already logged' do
+ let(:params) do
+ default_params.tap { |p| p[:tags] = [{ key: 'tag1', value: 'a' }, { key: 'tag1', value: 'b' }] }
+ end
+
+ it 'logs only 1', :aggregate_failures do
+ candidate.metadata.reload
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(candidate2.metadata.size).to eq(1)
+ end
+ end
+
describe 'Error Cases' do
context 'when required metric key is missing' do
let(:params) { default_params.tap { |p| p[:metrics] = [p[:metrics][0].delete(:key)] } }