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[
|
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-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
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
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-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
|
|
|
|
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
|