gitlab-ce/spec/requests/projects/ml/models_controller_spec.rb

202 lines
5.3 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Projects::Ml::ModelsController, feature_category: :mlops do
let_it_be(:project) { create(:project) }
let_it_be(:user) { project.first_owner }
let_it_be(:model1) { create(:ml_models, :with_versions, project: project) }
let_it_be(:model2) { create(:ml_models, project: project) }
let_it_be(:model3) { create(:ml_models, project: project) }
let_it_be(:model_in_different_project) { create(:ml_models) }
let(:read_model_registry) { true }
let(:write_model_registry) { true }
let(:params) { {} }
before do
allow(Ability).to receive(:allowed?).and_call_original
allow(Ability).to receive(:allowed?)
.with(user, :read_model_registry, project)
.and_return(read_model_registry)
allow(Ability).to receive(:allowed?)
.with(user, :write_model_registry, project)
.and_return(write_model_registry)
sign_in(user)
end
describe 'GET index' do
subject(:index_request) do
list_models
response
end
it 'renders the template' do
expect(index_request).to render_template('projects/ml/models/index')
end
it 'fetches the models using the finder' do
expect(::Projects::Ml::ModelFinder).to receive(:new).with(project, {}).and_call_original
index_request
end
it 'fetches the correct variables', :aggregate_failures do
stub_const("Projects::Ml::ModelsController::MAX_MODELS_PER_PAGE", 2)
index_request
page_models = [model3, model2]
all_models = [model3, model2, model1]
expect(assigns(:paginator).records).to match_array(page_models)
expect(assigns(:model_count)).to be all_models.count
end
it 'does not perform N+1 sql queries' do
list_models
control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) { list_models }
create_list(:ml_model_versions, 2, model: model1)
create_list(:ml_model_versions, 2, model: model2)
create_list(:ml_models, 4, project: project)
expect { list_models }.not_to exceed_all_query_limit(control_count)
end
context 'when user does not have access' do
let(:read_model_registry) { false }
it 'renders 404' do
is_expected.to have_gitlab_http_status(:not_found)
end
end
context 'with search params' do
let(:params) { { name: 'some_name', order_by: 'name', sort: 'asc' } }
it 'passes down params to the finder' do
expect(Projects::Ml::ModelFinder).to receive(:new).and_call_original do |_exp, params|
expect(params.to_h).to include({
name: 'some_name',
order_by: 'name',
sort: 'asc'
})
end
index_request
end
end
describe 'pagination' do
before do
stub_const("Projects::Ml::ModelsController::MAX_MODELS_PER_PAGE", 2)
end
it 'paginates', :aggregate_failures do
list_models
paginator = assigns(:paginator)
expect(paginator.records).to match_array([model3, model2])
list_models({ cursor: paginator.cursor_for_next_page })
expect(assigns(:paginator).records.first).to eq(model1)
end
end
end
describe 'show' do
let(:model_id) { model1.id }
let(:request_project) { model1.project }
subject(:show_request) do
show_model
response
end
before do
show_request
end
it 'renders the template' do
is_expected.to render_template('projects/ml/models/show')
end
it 'fetches the correct model' do
show_request
expect(assigns(:model)).to eq(model1)
end
context 'when model id does not exist' do
let(:model_id) { non_existing_record_id }
it { is_expected.to have_gitlab_http_status(:not_found) }
end
context 'when model project does not match project id' do
let(:request_project) { model_in_different_project.project }
it { is_expected.to have_gitlab_http_status(:not_found) }
end
context 'when user does not have access' do
let(:read_model_registry) { false }
it { is_expected.to have_gitlab_http_status(:not_found) }
end
end
describe 'destroy' do
let(:model_for_deletion) do
create(:ml_models, project: project)
end
let(:model_id) { model_for_deletion.id }
subject(:delete_request) do
delete_model
response
end
it 'deletes the model', :aggregate_failures do
is_expected.to have_gitlab_http_status(:found)
expect(flash[:notice]).to eq('Model removed')
expect(response).to redirect_to("/#{project.full_path}/-/ml/models")
expect { Ml::Model.find(id: model_id) }.to raise_error(ActiveRecord::RecordNotFound)
end
context 'when model does not exist' do
let(:model_id) { non_existing_record_id }
it { is_expected.to have_gitlab_http_status(:not_found) }
end
describe 'when user does not have write_model_registry rights' do
let(:write_model_registry) { false }
it { is_expected.to have_gitlab_http_status(:not_found) }
end
end
private
def list_models(new_params = nil)
get project_ml_models_path(project), params: new_params || params
end
def show_model
get project_ml_model_path(request_project, model_id)
end
def delete_model
delete project_ml_model_path(project, model_id)
end
end