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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
|
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop'
require_relative '../../../../rubocop/cop/migration/create_table_with_foreign_keys'
RSpec.describe RuboCop::Cop::Migration::CreateTableWithForeignKeys, type: :rubocop do
include CopHelper
let(:cop) { described_class.new }
context 'outside of a migration' do
it 'does not register any offenses' do
expect_no_offenses(<<~RUBY)
def up
create_table(:foo) do |t|
t.references :bar, foreign_key: { on_delete: 'cascade' }
t.references :zoo, foreign_key: { on_delete: 'cascade' }
end
end
RUBY
end
end
context 'in a migration' do
before do
allow(cop).to receive(:in_migration?).and_return(true)
end
context 'without foreign key' do
it 'does not register any offenses' do
expect_no_offenses(<<~RUBY)
def up
create_table(:foo) do |t|
t.references :bar
end
end
RUBY
end
end
context 'with foreign key' do
context 'with just one foreign key' do
context 'when the foreign_key targets a high traffic table' do
context 'when the foreign_key has to_table option set' do
it 'does not register any offenses' do
expect_no_offenses(<<~RUBY)
def up
create_table(:foo) do |t|
t.references :project, "foreign_key" => { on_delete: 'cascade', to_table: 'projects' }
end
end
RUBY
end
end
context 'when the foreign_key does not have to_table option set' do
it 'does not register any offenses' do
expect_no_offenses(<<~RUBY)
def up
create_table(:foo) do |t|
t.references :project, foreign_key: { on_delete: 'cascade' }
end
end
RUBY
end
end
end
context 'when the foreign_key does not target a high traffic table' do
it 'does not register any offenses' do
expect_no_offenses(<<~RUBY)
def up
create_table(:foo) do |t|
t.references :bar, foreign_key: { on_delete: 'cascade' }
end
end
RUBY
end
end
end
context 'with more than one foreign keys' do
let(:offense) do
'Creating a table with more than one foreign key at once violates our migration style guide. ' \
'For more details check the https://docs.gitlab.com/ee/development/migration_style_guide.html#examples'
end
shared_examples 'target to high traffic table' do |dsl_method, table_name|
context 'when the target is defined as option' do
it 'registers an offense ' do
expect_offense(<<~RUBY)
def up
create_table(:foo) do |t|
^^^^^^^^^^^^^^^^^^ #{offense}
t.#{dsl_method} :#{table_name.singularize} #{explicit_target_opts}
t.#{dsl_method} :zoo #{implicit_target_opts}
end
end
RUBY
end
end
context 'when the target has implicit definition' do
it 'registers an offense ' do
expect_offense(<<~RUBY)
def up
create_table(:foo) do |t|
^^^^^^^^^^^^^^^^^^ #{offense}
t.#{dsl_method} :#{table_name.singularize} #{implicit_target_opts}
t.#{dsl_method} :zoo #{implicit_target_opts}
end
end
RUBY
end
end
end
shared_context 'when there is a target to a high traffic table' do |dsl_method|
%w[
audit_events
ci_build_trace_sections
ci_builds
ci_builds_metadata
ci_job_artifacts
ci_pipeline_variables
ci_pipelines
ci_stages
deployments
events
gitlab_subscriptions
issues
merge_request_diff_commits
merge_request_diff_files
merge_request_diffs
merge_request_metrics
merge_requests
namespaces
note_diff_files
notes
project_authorizations
projects
project_ci_cd_settings
project_features
push_event_payloads
resource_label_events
routes
sent_notifications
system_note_metadata
taggings
todos
users
web_hook_logs
].each do |table|
let(:table_name) { table }
it_behaves_like 'target to high traffic table', dsl_method, table
end
end
context 'when the foreign keys are defined as options' do
context 'when there is no target to a high traffic table' do
it 'does not register any offenses' do
expect_no_offenses(<<~RUBY)
def up
create_table(:foo) do |t|
t.references :bar, foreign_key: { on_delete: 'cascade', to_table: :bars }
t.references :zoo, 'foreign_key' => { on_delete: 'cascade' }
t.references :john, 'foreign_key' => { on_delete: 'cascade' }
t.references :doe, 'foreign_key' => { on_delete: 'cascade', to_table: 'doe' }
end
end
RUBY
end
end
include_context 'when there is a target to a high traffic table', :references do
let(:explicit_target_opts) { ", foreign_key: { to_table: :#{table_name} }" }
let(:implicit_target_opts) { ", foreign_key: true" }
end
end
context 'when the foreign keys are defined by standlone migration helper' do
context 'when there is no target to a high traffic table' do
it 'does not register any offenses' do
expect_no_offenses(<<~RUBY)
def up
create_table(:foo) do |t|
t.foreign_key :bar
t.foreign_key :zoo, to_table: 'zoos'
end
end
RUBY
end
end
include_context 'when there is a target to a high traffic table', :foreign_key do
let(:explicit_target_opts) { ", to_table: :#{table_name}" }
let(:implicit_target_opts) { }
end
end
end
end
end
end
|