debian-mirror-gitlab/spec/db/docs_spec.rb

204 lines
6.8 KiB
Ruby
Raw Normal View History

2022-07-16 23:28:13 +05:30
# frozen_string_literal: true
require 'spec_helper'
2023-03-04 22:38:38 +05:30
RSpec.shared_examples 'validate dictionary' do |objects, directory_path, required_fields|
context 'for each object' do
let(:directory_path) { directory_path }
2022-07-16 23:28:13 +05:30
let(:metadata_allowed_fields) do
2023-03-04 22:38:38 +05:30
required_fields + %i[
2023-03-17 16:20:25 +05:30
feature_categories
2022-07-16 23:28:13 +05:30
classes
description
introduced_by_url
milestone
2023-03-04 22:38:38 +05:30
gitlab_schema
]
2022-07-16 23:28:13 +05:30
end
let(:metadata) do
2023-03-04 22:38:38 +05:30
objects.each_with_object({}) do |object_name, hash|
next unless File.exist?(object_metadata_file_path(object_name))
2022-07-16 23:28:13 +05:30
2023-03-04 22:38:38 +05:30
hash[object_name] ||= load_object_metadata(required_fields, object_name)
2022-07-16 23:28:13 +05:30
end
end
2023-04-23 21:23:45 +05:30
# This list is used to provide temporary exceptions for feature categories
# that are transitioning and not yet in the feature_categories.yml file
# any additions here should be accompanied by a link to an issue link
let(:valid_feature_categories) do
[
'jihu' # https://gitlab.com/gitlab-org/database-team/team-tasks/-/issues/192
]
end
let(:all_feature_categories) do
YAML.load_file(Rails.root.join('config/feature_categories.yml')) + valid_feature_categories
end
2023-03-04 22:38:38 +05:30
let(:objects_without_metadata) do
objects.reject { |t| metadata.has_key?(t) }
2022-07-16 23:28:13 +05:30
end
2023-03-04 22:38:38 +05:30
let(:objects_without_valid_metadata) do
2022-07-16 23:28:13 +05:30
metadata.select { |_, t| t.has_key?(:error) }.keys
end
2023-03-04 22:38:38 +05:30
let(:objects_with_disallowed_fields) do
2022-07-16 23:28:13 +05:30
metadata.select { |_, t| t.has_key?(:disallowed_fields) }.keys
end
2023-03-04 22:38:38 +05:30
let(:objects_with_missing_required_fields) do
2022-07-16 23:28:13 +05:30
metadata.select { |_, t| t.has_key?(:missing_required_fields) }.keys
end
2023-03-17 16:20:25 +05:30
let(:objects_with_invalid_feature_category) do
metadata.select { |_, t| t.has_key?(:invalid_feature_category) }.keys
end
2022-07-16 23:28:13 +05:30
it 'has a metadata file' do
2023-03-04 22:38:38 +05:30
expect(objects_without_metadata).to be_empty, multiline_error(
2022-07-16 23:28:13 +05:30
'Missing metadata files',
2023-03-04 22:38:38 +05:30
objects_without_metadata.map { |t| " #{object_metadata_file(t)}" }
2022-07-16 23:28:13 +05:30
)
end
it 'has a valid metadata file' do
2023-03-04 22:38:38 +05:30
expect(objects_without_valid_metadata).to be_empty, object_metadata_errors(
2022-07-16 23:28:13 +05:30
'Table metadata files with errors',
:error,
2023-03-04 22:38:38 +05:30
objects_without_valid_metadata
2022-07-16 23:28:13 +05:30
)
end
2023-03-17 16:20:25 +05:30
it 'has a valid feature category' do
2023-04-23 21:23:45 +05:30
message = <<~TEXT.chomp
Please use a category from https://about.gitlab.com/handbook/product/categories/#categories-a-z
Table metadata files with an invalid feature category
TEXT
2023-03-17 16:20:25 +05:30
expect(objects_with_invalid_feature_category).to be_empty, object_metadata_errors(
2023-04-23 21:23:45 +05:30
message,
:invalid_feature_category,
2023-03-17 16:20:25 +05:30
objects_with_invalid_feature_category
)
end
2022-07-16 23:28:13 +05:30
it 'has a valid metadata file with allowed fields' do
2023-03-04 22:38:38 +05:30
expect(objects_with_disallowed_fields).to be_empty, object_metadata_errors(
2022-07-16 23:28:13 +05:30
'Table metadata files with disallowed fields',
:disallowed_fields,
2023-03-04 22:38:38 +05:30
objects_with_disallowed_fields
2022-07-16 23:28:13 +05:30
)
end
it 'has a valid metadata file without missing fields' do
2023-03-04 22:38:38 +05:30
expect(objects_with_missing_required_fields).to be_empty, object_metadata_errors(
2022-07-16 23:28:13 +05:30
'Table metadata files with missing fields',
:missing_required_fields,
2023-03-04 22:38:38 +05:30
objects_with_missing_required_fields
2022-07-16 23:28:13 +05:30
)
end
end
private
2023-03-04 22:38:38 +05:30
def object_metadata_file(object_name)
File.join(directory_path, "#{object_name}.yml")
2022-07-16 23:28:13 +05:30
end
2023-03-04 22:38:38 +05:30
def object_metadata_file_path(object_name)
Rails.root.join(object_metadata_file(object_name))
2022-07-16 23:28:13 +05:30
end
2023-04-23 21:23:45 +05:30
def invalid_feature_categories(object_feature_categories)
2023-03-17 16:20:25 +05:30
return false unless object_feature_categories.present?
2023-04-23 21:23:45 +05:30
object_feature_categories - all_feature_categories
2023-03-17 16:20:25 +05:30
end
2023-03-04 22:38:38 +05:30
def load_object_metadata(required_fields, object_name)
2022-07-16 23:28:13 +05:30
result = {}
begin
2023-03-04 22:38:38 +05:30
result[:metadata] = YAML.safe_load(File.read(object_metadata_file_path(object_name))).deep_symbolize_keys
2022-07-16 23:28:13 +05:30
disallowed_fields = (result[:metadata].keys - metadata_allowed_fields)
2023-03-04 22:38:38 +05:30
result[:disallowed_fields] = "fields not allowed: #{disallowed_fields.join(', ')}" unless disallowed_fields.empty?
2022-07-16 23:28:13 +05:30
2023-03-04 22:38:38 +05:30
missing_required_fields = (required_fields - result[:metadata].reject { |_, v| v.blank? }.keys)
2022-07-16 23:28:13 +05:30
unless missing_required_fields.empty?
result[:missing_required_fields] = "missing required fields: #{missing_required_fields.join(', ')}"
end
2023-03-17 16:20:25 +05:30
if required_fields.include?(:feature_categories)
object_feature_categories = result.dig(:metadata, :feature_categories)
2023-04-23 21:23:45 +05:30
if (invalid = invalid_feature_categories(object_feature_categories)).any?
result[:invalid_feature_category] = "invalid feature category: #{invalid.join(', ')}"
2023-03-17 16:20:25 +05:30
end
end
2022-07-16 23:28:13 +05:30
rescue Psych::SyntaxError => ex
result[:error] = ex.message
end
result
end
2023-03-04 22:38:38 +05:30
# rubocop:disable Naming/HeredocDelimiterNaming
def object_metadata_errors(title, field, objects)
lines = objects.map do |object_name|
2022-07-16 23:28:13 +05:30
<<~EOM
2023-03-04 22:38:38 +05:30
#{object_metadata_file(object_name)}
#{metadata[object_name][field]}
2022-07-16 23:28:13 +05:30
EOM
end
multiline_error(title, lines)
end
def multiline_error(title, lines)
<<~EOM
#{title}:
#{lines.join("\n")}
EOM
end
2023-03-04 22:38:38 +05:30
# rubocop:enable Naming/HeredocDelimiterNaming
end
RSpec.describe 'Views documentation', feature_category: :database do
database_base_models = Gitlab::Database.database_base_models.select { |k, _| k != 'geo' }
views = database_base_models.flat_map { |_, m| m.connection.views }.sort.uniq
directory_path = File.join('db', 'docs', 'views')
required_fields = %i[feature_categories view_name gitlab_schema]
include_examples 'validate dictionary', views, directory_path, required_fields
end
RSpec.describe 'Tables documentation', feature_category: :database do
database_base_models = Gitlab::Database.database_base_models.select { |k, _| k != 'geo' }
tables = database_base_models.flat_map { |_, m| m.connection.tables }.sort.uniq
directory_path = File.join('db', 'docs')
required_fields = %i[feature_categories table_name gitlab_schema]
include_examples 'validate dictionary', tables, directory_path, required_fields
2022-07-16 23:28:13 +05:30
end
2023-03-17 16:20:25 +05:30
RSpec.describe 'Deleted tables documentation', feature_category: :database do
directory_path = File.join('db', 'docs', 'deleted_tables')
tables = Dir.glob(File.join(directory_path, '*.yml')).map { |f| File.basename(f, '.yml') }.sort.uniq
required_fields = %i[table_name gitlab_schema removed_by_url removed_in_milestone]
include_examples 'validate dictionary', tables, directory_path, required_fields
end
RSpec.describe 'Deleted views documentation', feature_category: :database do
directory_path = File.join('db', 'docs', 'deleted_views')
views = Dir.glob(File.join(directory_path, '*.yml')).map { |f| File.basename(f, '.yml') }.sort.uniq
required_fields = %i[view_name gitlab_schema removed_by_url removed_in_milestone]
include_examples 'validate dictionary', views, directory_path, required_fields
end