1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Database Documentation' do
context 'for each table' do
let(:all_tables) do
Gitlab::Database.database_base_models.flat_map { |_, m| m.connection.tables }.sort.uniq
end
let(:metadata_required_fields) do
%i(
feature_categories
table_name
)
end
let(:metadata_allowed_fields) do
metadata_required_fields + %i(
classes
description
introduced_by_url
milestone
)
end
let(:metadata) do
all_tables.each_with_object({}) do |table_name, hash|
next unless File.exist?(table_metadata_file_path(table_name))
hash[table_name] ||= load_table_metadata(table_name)
end
end
let(:tables_without_metadata) do
all_tables.reject { |t| metadata.has_key?(t) }
end
let(:tables_without_valid_metadata) do
metadata.select { |_, t| t.has_key?(:error) }.keys
end
let(:tables_with_disallowed_fields) do
metadata.select { |_, t| t.has_key?(:disallowed_fields) }.keys
end
let(:tables_with_missing_required_fields) do
metadata.select { |_, t| t.has_key?(:missing_required_fields) }.keys
end
it 'has a metadata file' do
expect(tables_without_metadata).to be_empty, multiline_error(
'Missing metadata files',
tables_without_metadata.map { |t| " #{table_metadata_file(t)}" }
)
end
it 'has a valid metadata file' do
expect(tables_without_valid_metadata).to be_empty, table_metadata_errors(
'Table metadata files with errors',
:error,
tables_without_valid_metadata
)
end
it 'has a valid metadata file with allowed fields' do
expect(tables_with_disallowed_fields).to be_empty, table_metadata_errors(
'Table metadata files with disallowed fields',
:disallowed_fields,
tables_with_disallowed_fields
)
end
it 'has a valid metadata file without missing fields' do
expect(tables_with_missing_required_fields).to be_empty, table_metadata_errors(
'Table metadata files with missing fields',
:missing_required_fields,
tables_with_missing_required_fields
)
end
end
private
def table_metadata_file(table_name)
File.join('db', 'docs', "#{table_name}.yml")
end
def table_metadata_file_path(table_name)
Rails.root.join(table_metadata_file(table_name))
end
def load_table_metadata(table_name)
result = {}
begin
result[:metadata] = YAML.safe_load(File.read(table_metadata_file_path(table_name))).deep_symbolize_keys
disallowed_fields = (result[:metadata].keys - metadata_allowed_fields)
unless disallowed_fields.empty?
result[:disallowed_fields] = "fields not allowed: #{disallowed_fields.join(', ')}"
end
missing_required_fields = (metadata_required_fields - result[:metadata].reject { |_, v| v.blank? }.keys)
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
def table_metadata_errors(title, field, tables)
lines = tables.map do |table_name|
<<~EOM
#{table_metadata_file(table_name)}
#{metadata[table_name][field]}
EOM
end
multiline_error(title, lines)
end
def multiline_error(title, lines)
<<~EOM
#{title}:
#{lines.join("\n")}
EOM
end
end
|