From ccee7abf9112370a9ab8128988d5377db3dd353c Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sun, 3 Aug 2025 21:48:14 -0700 Subject: [PATCH] Add backend support for retrieving database schema results This is split out from https://gitlab.com/gitlab-org/gitlab/-/merge_requests/199796 to reduce the review overhead. Relates to https://gitlab.com/gitlab-org/gitlab/-/issues/467544. Changelog: added --- .../admin/database_diagnostics_controller.rb | 44 +++++++++- config/routes/admin.rb | 2 + .../database_diagnostics_controller_spec.rb | 88 +++++++++++++++++++ 3 files changed, 130 insertions(+), 4 deletions(-) diff --git a/app/controllers/admin/database_diagnostics_controller.rb b/app/controllers/admin/database_diagnostics_controller.rb index d7460f35f4dca7..d0feea6dc24203 100644 --- a/app/controllers/admin/database_diagnostics_controller.rb +++ b/app/controllers/admin/database_diagnostics_controller.rb @@ -3,20 +3,56 @@ module Admin class DatabaseDiagnosticsController < Admin::ApplicationController feature_category :database - authorize! :read_admin_database_diagnostics, only: %i[index run_collation_check collation_check_results] + authorize! :read_admin_database_diagnostics, + only: %i[index run_collation_check collation_check_results run_schema_check schema_check_results] + + WORKER_CONFIGS = { + collation: { + worker: ::Database::CollationCheckerWorker, + cache_key: ::Database::CollationCheckerWorker::COLLATION_CHECK_CACHE_KEY + }, + schema: { + worker: ::Database::SchemaCheckerWorker, + cache_key: ::Database::SchemaCheckerWorker::SCHEMA_CHECK_CACHE_KEY + } + }.freeze def index # Just render the view end def run_collation_check - job_id = ::Database::CollationCheckerWorker.perform_async # rubocop:disable CodeReuse/Worker -- Simple direct call + run_check(:collation) + end - render json: { status: 'scheduled', job_id: job_id } + def run_schema_check + run_check(:schema) end def collation_check_results - results_json = Rails.cache.read(::Database::CollationCheckerWorker::COLLATION_CHECK_CACHE_KEY) + check_results(:collation) + end + + def schema_check_results + check_results(:schema) + end + + private + + def run_check(check_type) + worker_class = WORKER_CONFIGS[check_type][:worker] + job_id = worker_class.perform_async + + if job_id + render json: { status: 'scheduled', job_id: job_id } + else + render json: { error: 'Failed to schedule job' }, status: :internal_server_error + end + end + + def check_results(check_type) + cache_key = WORKER_CONFIGS[check_type][:cache_key] + results_json = Rails.cache.read(cache_key) if results_json.present? results = Gitlab::Json.parse(results_json) diff --git a/config/routes/admin.rb b/config/routes/admin.rb index 81e89b008b81ac..a810279dfc664e 100644 --- a/config/routes/admin.rb +++ b/config/routes/admin.rb @@ -124,6 +124,8 @@ collection do post :run_collation_check get :collation_check_results + post :run_schema_check + get :schema_check_results end end diff --git a/spec/requests/admin/database_diagnostics_controller_spec.rb b/spec/requests/admin/database_diagnostics_controller_spec.rb index 871c4bdf2f4ce8..dbba9dbf90b57c 100644 --- a/spec/requests/admin/database_diagnostics_controller_spec.rb +++ b/spec/requests/admin/database_diagnostics_controller_spec.rb @@ -74,6 +74,46 @@ expect(response).to have_gitlab_http_status(:ok) expect(json_response).to include('status' => 'scheduled', 'job_id' => 'job_id') end + + it 'returns 500 response when worker fails to schedule' do + expect(::Database::CollationCheckerWorker).to receive(:perform_async).and_return(nil) + + send_request + + expect(response).to have_gitlab_http_status(:internal_server_error) + expect(json_response).to include('error' => 'Failed to schedule job') + end + end + end + + describe 'POST /admin/database_diagnostics/run_schema_check' do + subject(:send_request) do + post run_schema_check_admin_database_diagnostics_path(format: :json) + end + + it_behaves_like 'unauthorized request' + + context 'when admin mode is enabled', :enable_admin_mode do + before do + login_as(admin) + end + + it 'returns 200 response and schedules the worker' do + expect(::Database::SchemaCheckerWorker).to receive(:perform_async).and_return('schema_job_id') + + send_request + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to include('status' => 'scheduled', 'job_id' => 'schema_job_id') + end + + it 'returns 500 response when worker fails to schedule' do + expect(::Database::SchemaCheckerWorker).to receive(:perform_async).and_return(nil) + + send_request + + expect(response).to have_gitlab_http_status(:internal_server_error) + expect(json_response).to include('error' => 'Failed to schedule job') + end end end @@ -125,4 +165,52 @@ end end end + + describe 'GET /admin/database_diagnostics/schema_check_results' do + subject(:send_request) do + get schema_check_results_admin_database_diagnostics_path(format: :json) + end + + it_behaves_like 'unauthorized request' + + context 'when admin mode is enabled', :enable_admin_mode do + before do + login_as(admin) + end + + context 'when results are available' do + let(:results) do + { + metadata: { last_run_at: Time.current.iso8601 }, + schema_check_results: { + main: { + missing_indexes: [] + } + } + } + end + + it 'returns 200 response with the results' do + allow(Rails.cache).to receive(:read) + expect(Rails.cache).to receive(:read) + .with(::Database::SchemaCheckerWorker::SCHEMA_CHECK_CACHE_KEY) + .and_return(results.to_json) + + send_request + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to include('schema_check_results', 'metadata') + end + end + + context 'when no results are available' do + it 'returns 404 response' do + send_request + + expect(response).to have_gitlab_http_status(:not_found) + expect(json_response).to include('error' => 'No results available yet') + end + end + end + end end -- GitLab