active_record_doctor 1.11.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +41 -14
- data/lib/active_record_doctor/config/loader.rb +1 -1
- data/lib/active_record_doctor/detectors/base.rb +30 -15
- data/lib/active_record_doctor/detectors/extraneous_indexes.rb +14 -9
- data/lib/active_record_doctor/detectors/incorrect_boolean_presence_validation.rb +1 -1
- data/lib/active_record_doctor/detectors/incorrect_dependent_option.rb +44 -31
- data/lib/active_record_doctor/detectors/mismatched_foreign_key_type.rb +1 -1
- data/lib/active_record_doctor/detectors/missing_non_null_constraint.rb +2 -2
- data/lib/active_record_doctor/detectors/missing_unique_indexes.rb +73 -23
- data/lib/active_record_doctor/detectors/short_primary_key_type.rb +3 -3
- data/lib/active_record_doctor/detectors/unindexed_foreign_keys.rb +34 -7
- data/lib/active_record_doctor/logger/hierarchical.rb +1 -1
- data/lib/active_record_doctor/railtie.rb +1 -1
- data/lib/active_record_doctor/runner.rb +1 -1
- data/lib/active_record_doctor/utils.rb +21 -0
- data/lib/active_record_doctor/version.rb +1 -1
- data/lib/active_record_doctor.rb +2 -0
- data/lib/generators/active_record_doctor/add_indexes/add_indexes_generator.rb +14 -14
- data/lib/tasks/active_record_doctor.rake +2 -2
- metadata +11 -47
- data/test/active_record_doctor/config/loader_test.rb +0 -120
- data/test/active_record_doctor/config_test.rb +0 -116
- data/test/active_record_doctor/detectors/disable_test.rb +0 -30
- data/test/active_record_doctor/detectors/extraneous_indexes_test.rb +0 -224
- data/test/active_record_doctor/detectors/incorrect_boolean_presence_validation_test.rb +0 -79
- data/test/active_record_doctor/detectors/incorrect_dependent_option_test.rb +0 -472
- data/test/active_record_doctor/detectors/incorrect_length_validation_test.rb +0 -107
- data/test/active_record_doctor/detectors/mismatched_foreign_key_type_test.rb +0 -116
- data/test/active_record_doctor/detectors/missing_foreign_keys_test.rb +0 -70
- data/test/active_record_doctor/detectors/missing_non_null_constraint_test.rb +0 -273
- data/test/active_record_doctor/detectors/missing_presence_validation_test.rb +0 -232
- data/test/active_record_doctor/detectors/missing_unique_indexes_test.rb +0 -327
- data/test/active_record_doctor/detectors/short_primary_key_type_test.rb +0 -72
- data/test/active_record_doctor/detectors/undefined_table_references_test.rb +0 -55
- data/test/active_record_doctor/detectors/unindexed_deleted_at_test.rb +0 -177
- data/test/active_record_doctor/detectors/unindexed_foreign_keys_test.rb +0 -78
- data/test/active_record_doctor/runner_test.rb +0 -41
- data/test/generators/active_record_doctor/add_indexes/add_indexes_generator_test.rb +0 -131
- data/test/setup.rb +0 -124
@@ -18,28 +18,44 @@ module ActiveRecordDoctor
|
|
18
18
|
|
19
19
|
private
|
20
20
|
|
21
|
-
def message(table:,
|
21
|
+
def message(table:, columns:)
|
22
22
|
# rubocop:disable Layout/LineLength
|
23
|
-
"add an index on #{table}
|
23
|
+
"add an index on #{table}(#{columns.join(', ')}) - foreign keys are often used in database lookups and should be indexed for performance reasons"
|
24
24
|
# rubocop:enable Layout/LineLength
|
25
25
|
end
|
26
26
|
|
27
27
|
def detect
|
28
28
|
each_table(except: config(:ignore_tables)) do |table|
|
29
29
|
each_column(table, except: config(:ignore_columns)) do |column|
|
30
|
-
next unless foreign_key?(column)
|
30
|
+
next unless named_like_foreign_key?(column) || foreign_key?(table, column)
|
31
31
|
next if indexed?(table, column)
|
32
32
|
next if indexed_as_polymorphic?(table, column)
|
33
|
+
next if connection.primary_key(table) == column.name
|
33
34
|
|
34
|
-
|
35
|
+
type_column_name = type_column_name(column)
|
36
|
+
|
37
|
+
columns =
|
38
|
+
if column_exists?(table, type_column_name)
|
39
|
+
[type_column_name, column.name]
|
40
|
+
else
|
41
|
+
[column.name]
|
42
|
+
end
|
43
|
+
|
44
|
+
problem!(table: table, columns: columns)
|
35
45
|
end
|
36
46
|
end
|
37
47
|
end
|
38
48
|
|
39
|
-
def
|
49
|
+
def named_like_foreign_key?(column)
|
40
50
|
column.name.end_with?("_id")
|
41
51
|
end
|
42
52
|
|
53
|
+
def foreign_key?(table, column)
|
54
|
+
connection.foreign_keys(table).any? do |foreign_key|
|
55
|
+
foreign_key.column == column.name
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
43
59
|
def indexed?(table, column)
|
44
60
|
connection.indexes(table).any? do |index|
|
45
61
|
index.columns.first == column.name
|
@@ -47,9 +63,20 @@ module ActiveRecordDoctor
|
|
47
63
|
end
|
48
64
|
|
49
65
|
def indexed_as_polymorphic?(table, column)
|
50
|
-
type_column_name = column.name.sub(/_id\Z/, "_type")
|
51
66
|
connection.indexes(table).any? do |index|
|
52
|
-
index.columns == [type_column_name, column.name]
|
67
|
+
index.columns[0, 2] == [type_column_name(column), column.name]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def column_exists?(table, column_name)
|
72
|
+
connection.columns(table).any? { |column| column.name == column_name }
|
73
|
+
end
|
74
|
+
|
75
|
+
def type_column_name(column)
|
76
|
+
if column.name.end_with?("_id")
|
77
|
+
column.name.sub(/_id\Z/, "_type")
|
78
|
+
else
|
79
|
+
"#{column.name}_type"
|
53
80
|
end
|
54
81
|
end
|
55
82
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveRecordDoctor # :nodoc:
|
4
|
-
# An
|
4
|
+
# An execution environment for active_record_doctor that provides a config
|
5
5
|
# and an output device for use by detectors.
|
6
6
|
class Runner
|
7
7
|
# io is injected via constructor parameters to facilitate testing.
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecordDoctor
|
4
|
+
module Utils # :nodoc:
|
5
|
+
class << self
|
6
|
+
def postgresql?(connection = ActiveRecord::Base.connection)
|
7
|
+
["PostgreSQL", "PostGIS"].include?(connection.adapter_name)
|
8
|
+
end
|
9
|
+
|
10
|
+
def mysql?(connection = ActiveRecord::Base.connection)
|
11
|
+
connection.adapter_name == "Mysql2"
|
12
|
+
end
|
13
|
+
|
14
|
+
def expression_indexes_unsupported?(connection = ActiveRecord::Base.connection)
|
15
|
+
(ActiveRecord::VERSION::STRING < "5.0") ||
|
16
|
+
# Active Record is unable to correctly parse expression indexes for MySQL.
|
17
|
+
(mysql?(connection) && ActiveRecord::VERSION::STRING < "7.1")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/active_record_doctor.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_record_doctor/railtie" if defined?(Rails) && defined?(Rails::Railtie)
|
4
|
+
require "active_record_doctor/utils"
|
4
5
|
require "active_record_doctor/logger"
|
5
6
|
require "active_record_doctor/logger/dummy"
|
6
7
|
require "active_record_doctor/logger/hierarchical"
|
@@ -25,6 +26,7 @@ require "active_record_doctor/runner"
|
|
25
26
|
require "active_record_doctor/version"
|
26
27
|
require "active_record_doctor/config"
|
27
28
|
require "active_record_doctor/config/loader"
|
29
|
+
require "active_record_doctor/rake/task"
|
28
30
|
|
29
31
|
module ActiveRecordDoctor # :nodoc:
|
30
32
|
end
|
@@ -10,16 +10,16 @@ module ActiveRecordDoctor
|
|
10
10
|
migration_descriptions = read_migration_descriptions(path)
|
11
11
|
now = Time.now
|
12
12
|
|
13
|
-
migration_descriptions.each_with_index do |(table,
|
13
|
+
migration_descriptions.each_with_index do |(table, indexes), index|
|
14
14
|
timestamp = (now + index).strftime("%Y%m%d%H%M%S")
|
15
15
|
file_name = "db/migrate/#{timestamp}_index_foreign_keys_in_#{table}.rb"
|
16
|
-
create_file(file_name, content(table,
|
16
|
+
create_file(file_name, content(table, indexes).tap { |x| puts x })
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
20
|
private
|
21
21
|
|
22
|
-
INPUT_LINE = /^add an index on (\w+)
|
22
|
+
INPUT_LINE = /^add an index on (\w+)\((.+)\) - .*$/.freeze
|
23
23
|
private_constant :INPUT_LINE
|
24
24
|
|
25
25
|
def read_migration_descriptions(path)
|
@@ -34,41 +34,41 @@ module ActiveRecordDoctor
|
|
34
34
|
end
|
35
35
|
|
36
36
|
table = match[1]
|
37
|
-
|
37
|
+
columns = match[2].split(",").map(&:strip)
|
38
38
|
|
39
|
-
tables_to_columns[table] <<
|
39
|
+
tables_to_columns[table] << columns
|
40
40
|
end
|
41
41
|
|
42
42
|
tables_to_columns
|
43
43
|
end
|
44
44
|
|
45
|
-
def content(table,
|
45
|
+
def content(table, indexes)
|
46
46
|
# In order to properly indent the resulting code, we must disable the
|
47
47
|
# rubocop rule below.
|
48
48
|
|
49
49
|
<<MIGRATION
|
50
50
|
class IndexForeignKeysIn#{table.camelize} < ActiveRecord::Migration#{migration_version}
|
51
51
|
def change
|
52
|
-
#{add_indexes(table,
|
52
|
+
#{add_indexes(table, indexes)}
|
53
53
|
end
|
54
54
|
end
|
55
55
|
MIGRATION
|
56
56
|
end
|
57
57
|
|
58
|
-
def add_indexes(table,
|
59
|
-
|
60
|
-
add_index(table,
|
58
|
+
def add_indexes(table, indexes)
|
59
|
+
indexes.map do |columns|
|
60
|
+
add_index(table, columns)
|
61
61
|
end.join("\n")
|
62
62
|
end
|
63
63
|
|
64
|
-
def add_index(table,
|
64
|
+
def add_index(table, columns)
|
65
65
|
connection = ActiveRecord::Base.connection
|
66
66
|
|
67
|
-
index_name = connection.index_name(table,
|
67
|
+
index_name = connection.index_name(table, columns)
|
68
68
|
if index_name.size > connection.index_name_length
|
69
|
-
" add_index :#{table},
|
69
|
+
" add_index :#{table}, #{columns.inspect}, name: '#{index_name.first(connection.index_name_length)}'"
|
70
70
|
else
|
71
|
-
" add_index :#{table},
|
71
|
+
" add_index :#{table}, #{columns.inspect}"
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
@@ -19,6 +19,6 @@ ActiveRecordDoctor::Rake::Task.new do |task|
|
|
19
19
|
# This file is imported when active_record_doctor is being used as part of a
|
20
20
|
# Rails app so it's the right place for all Rails-specific settings.
|
21
21
|
task.deps = [:environment]
|
22
|
-
task.config_path =
|
23
|
-
task.setup = -> {
|
22
|
+
task.config_path = Rails.root.join(".active_record_doctor")
|
23
|
+
task.setup = -> { Rails.application.eager_load! }
|
24
24
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_record_doctor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.13.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Greg Navis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-12-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -100,28 +100,28 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - '='
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
103
|
+
version: 2.0.0.rc2
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - '='
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
110
|
+
version: 2.0.0.rc2
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: rubocop
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: 1.
|
117
|
+
version: 1.57.1
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: 1.
|
124
|
+
version: 1.57.1
|
125
125
|
description:
|
126
126
|
email:
|
127
127
|
- contact@gregnavis.com
|
@@ -159,33 +159,16 @@ files:
|
|
159
159
|
- lib/active_record_doctor/railtie.rb
|
160
160
|
- lib/active_record_doctor/rake/task.rb
|
161
161
|
- lib/active_record_doctor/runner.rb
|
162
|
+
- lib/active_record_doctor/utils.rb
|
162
163
|
- lib/active_record_doctor/version.rb
|
163
164
|
- lib/generators/active_record_doctor/add_indexes/USAGE
|
164
165
|
- lib/generators/active_record_doctor/add_indexes/add_indexes_generator.rb
|
165
166
|
- lib/tasks/active_record_doctor.rake
|
166
|
-
- test/active_record_doctor/config/loader_test.rb
|
167
|
-
- test/active_record_doctor/config_test.rb
|
168
|
-
- test/active_record_doctor/detectors/disable_test.rb
|
169
|
-
- test/active_record_doctor/detectors/extraneous_indexes_test.rb
|
170
|
-
- test/active_record_doctor/detectors/incorrect_boolean_presence_validation_test.rb
|
171
|
-
- test/active_record_doctor/detectors/incorrect_dependent_option_test.rb
|
172
|
-
- test/active_record_doctor/detectors/incorrect_length_validation_test.rb
|
173
|
-
- test/active_record_doctor/detectors/mismatched_foreign_key_type_test.rb
|
174
|
-
- test/active_record_doctor/detectors/missing_foreign_keys_test.rb
|
175
|
-
- test/active_record_doctor/detectors/missing_non_null_constraint_test.rb
|
176
|
-
- test/active_record_doctor/detectors/missing_presence_validation_test.rb
|
177
|
-
- test/active_record_doctor/detectors/missing_unique_indexes_test.rb
|
178
|
-
- test/active_record_doctor/detectors/short_primary_key_type_test.rb
|
179
|
-
- test/active_record_doctor/detectors/undefined_table_references_test.rb
|
180
|
-
- test/active_record_doctor/detectors/unindexed_deleted_at_test.rb
|
181
|
-
- test/active_record_doctor/detectors/unindexed_foreign_keys_test.rb
|
182
|
-
- test/active_record_doctor/runner_test.rb
|
183
|
-
- test/generators/active_record_doctor/add_indexes/add_indexes_generator_test.rb
|
184
|
-
- test/setup.rb
|
185
167
|
homepage: https://github.com/gregnavis/active_record_doctor
|
186
168
|
licenses:
|
187
169
|
- MIT
|
188
|
-
metadata:
|
170
|
+
metadata:
|
171
|
+
rubygems_mfa_required: 'true'
|
189
172
|
post_install_message:
|
190
173
|
rdoc_options: []
|
191
174
|
require_paths:
|
@@ -201,27 +184,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
201
184
|
- !ruby/object:Gem::Version
|
202
185
|
version: '0'
|
203
186
|
requirements: []
|
204
|
-
rubygems_version: 3.
|
187
|
+
rubygems_version: 3.3.26
|
205
188
|
signing_key:
|
206
189
|
specification_version: 4
|
207
190
|
summary: Identify database issues before they hit production.
|
208
|
-
test_files:
|
209
|
-
- test/active_record_doctor/config/loader_test.rb
|
210
|
-
- test/active_record_doctor/config_test.rb
|
211
|
-
- test/active_record_doctor/detectors/disable_test.rb
|
212
|
-
- test/active_record_doctor/detectors/extraneous_indexes_test.rb
|
213
|
-
- test/active_record_doctor/detectors/incorrect_boolean_presence_validation_test.rb
|
214
|
-
- test/active_record_doctor/detectors/incorrect_dependent_option_test.rb
|
215
|
-
- test/active_record_doctor/detectors/incorrect_length_validation_test.rb
|
216
|
-
- test/active_record_doctor/detectors/mismatched_foreign_key_type_test.rb
|
217
|
-
- test/active_record_doctor/detectors/missing_foreign_keys_test.rb
|
218
|
-
- test/active_record_doctor/detectors/missing_non_null_constraint_test.rb
|
219
|
-
- test/active_record_doctor/detectors/missing_presence_validation_test.rb
|
220
|
-
- test/active_record_doctor/detectors/missing_unique_indexes_test.rb
|
221
|
-
- test/active_record_doctor/detectors/short_primary_key_type_test.rb
|
222
|
-
- test/active_record_doctor/detectors/undefined_table_references_test.rb
|
223
|
-
- test/active_record_doctor/detectors/unindexed_deleted_at_test.rb
|
224
|
-
- test/active_record_doctor/detectors/unindexed_foreign_keys_test.rb
|
225
|
-
- test/active_record_doctor/runner_test.rb
|
226
|
-
- test/generators/active_record_doctor/add_indexes/add_indexes_generator_test.rb
|
227
|
-
- test/setup.rb
|
191
|
+
test_files: []
|
@@ -1,120 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class ActiveRecordDoctor::LoaderTest < Minitest::Test
|
4
|
-
def test_load_config
|
5
|
-
config_path = config_file(<<-CONFIG)
|
6
|
-
ActiveRecordDoctor.configure do |config|
|
7
|
-
config.global :ignore_tables, ["schema_migrations"]
|
8
|
-
|
9
|
-
config.detector :extraneous_indexes, ignore_tables: ["users"]
|
10
|
-
end
|
11
|
-
CONFIG
|
12
|
-
|
13
|
-
config = ActiveRecordDoctor.load_config(config_path)
|
14
|
-
|
15
|
-
assert_equal(
|
16
|
-
{ ignore_tables: ["schema_migrations"] },
|
17
|
-
config.globals
|
18
|
-
)
|
19
|
-
assert_equal(
|
20
|
-
{ extraneous_indexes: { ignore_tables: ["users"] } },
|
21
|
-
config.detectors
|
22
|
-
)
|
23
|
-
end
|
24
|
-
|
25
|
-
def test_load_config_raises_when_configuration_file_missing
|
26
|
-
exc = assert_raises(ActiveRecordDoctor::Error::ConfigurationFileMissing) do
|
27
|
-
ActiveRecordDoctor.load_config("/tmp/config.rb")
|
28
|
-
end
|
29
|
-
assert_equal("/tmp/config.rb", exc.config_path)
|
30
|
-
end
|
31
|
-
|
32
|
-
def test_load_config_raises_when_configuration_file_raises
|
33
|
-
config_path = config_file("1/0")
|
34
|
-
|
35
|
-
assert_raises(ActiveRecordDoctor::Error::ConfigurationError) do
|
36
|
-
ActiveRecordDoctor.load_config(config_path)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def test_load_config_raises_when_configure_not_called
|
41
|
-
config_path = config_file("# configure is not called")
|
42
|
-
|
43
|
-
assert_raises(ActiveRecordDoctor::Error::ConfigureNotCalled) do
|
44
|
-
ActiveRecordDoctor.load_config(config_path)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def test_load_config_raises_when_configure_called_twice
|
49
|
-
config_path = config_file(<<-CONFIG)
|
50
|
-
ActiveRecordDoctor.configure { |config| }
|
51
|
-
ActiveRecordDoctor.configure { |config| }
|
52
|
-
CONFIG
|
53
|
-
|
54
|
-
assert_raises(ActiveRecordDoctor::Error::ConfigureCalledTwice) do
|
55
|
-
ActiveRecordDoctor.load_config(config_path)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def test_load_config_raises_when_unrecognized_global_set
|
60
|
-
config_path = config_file(<<-CONFIG)
|
61
|
-
ActiveRecordDoctor.configure do |config|
|
62
|
-
config.global :user, "acme"
|
63
|
-
end
|
64
|
-
CONFIG
|
65
|
-
|
66
|
-
assert_raises(ActiveRecordDoctor::Error::UnrecognizedGlobalSetting) do
|
67
|
-
ActiveRecordDoctor.load_config(config_path)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def test_load_config_raises_when_global_set_twice
|
72
|
-
config_path = config_file(<<-CONFIG)
|
73
|
-
ActiveRecordDoctor.configure do |config|
|
74
|
-
config.global :ignore_tables, ["schema_migrations"]
|
75
|
-
config.global :ignore_tables, ["schema_migrations"]
|
76
|
-
end
|
77
|
-
CONFIG
|
78
|
-
|
79
|
-
assert_raises(ActiveRecordDoctor::Error::DuplicateGlobalSetting) do
|
80
|
-
ActiveRecordDoctor.load_config(config_path)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def test_load_config_raises_when_configured_unrecognized_detector
|
85
|
-
config_path = config_file(<<-CONFIG)
|
86
|
-
ActiveRecordDoctor.configure do |config|
|
87
|
-
config.detector :other_performance_issues, {}
|
88
|
-
end
|
89
|
-
CONFIG
|
90
|
-
|
91
|
-
assert_raises(ActiveRecordDoctor::Error::UnrecognizedDetectorName) do
|
92
|
-
ActiveRecordDoctor.load_config(config_path)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
def test_load_config_raises_when_detector_configured_twice
|
97
|
-
config_path = config_file(<<-CONFIG)
|
98
|
-
ActiveRecordDoctor.configure do |config|
|
99
|
-
config.detector :extraneous_indexes, ignore_tables: ["users"]
|
100
|
-
config.detector :extraneous_indexes, ignore_tables: ["users"]
|
101
|
-
end
|
102
|
-
CONFIG
|
103
|
-
|
104
|
-
assert_raises(ActiveRecordDoctor::Error::DetectorConfiguredTwice) do
|
105
|
-
ActiveRecordDoctor.load_config(config_path)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
def test_load_config_raises_when_provided_unrecognized_detector_setting
|
110
|
-
config_path = config_file(<<-CONFIG)
|
111
|
-
ActiveRecordDoctor.configure do |config|
|
112
|
-
config.detector :extraneous_indexes, { delay: 1 }
|
113
|
-
end
|
114
|
-
CONFIG
|
115
|
-
|
116
|
-
assert_raises(ActiveRecordDoctor::Error::UnrecognizedDetectorSettings) do
|
117
|
-
ActiveRecordDoctor.load_config(config_path)
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
@@ -1,116 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class ActiveRecordDoctor::ConfigTest < Minitest::Test
|
4
|
-
def test_merge_globals_empty
|
5
|
-
config1 = ActiveRecordDoctor::Config.new({}, {})
|
6
|
-
config2 = ActiveRecordDoctor::Config.new({}, {})
|
7
|
-
|
8
|
-
config = config1.merge(config2)
|
9
|
-
|
10
|
-
assert_equal({}, config.globals)
|
11
|
-
end
|
12
|
-
|
13
|
-
def test_merge_globals_in_config1
|
14
|
-
config1 = ActiveRecordDoctor::Config.new(
|
15
|
-
{ config1_global: "config1:config1_global" },
|
16
|
-
{}
|
17
|
-
)
|
18
|
-
config2 = ActiveRecordDoctor::Config.new({}, {})
|
19
|
-
|
20
|
-
config = config1.merge(config2)
|
21
|
-
|
22
|
-
assert_equal(
|
23
|
-
{ config1_global: "config1:config1_global" },
|
24
|
-
config.globals
|
25
|
-
)
|
26
|
-
end
|
27
|
-
|
28
|
-
def test_merge_globals_in_config2
|
29
|
-
config1 = ActiveRecordDoctor::Config.new({}, {})
|
30
|
-
config2 = ActiveRecordDoctor::Config.new(
|
31
|
-
{ config2_global: "config2:config2_global" },
|
32
|
-
{}
|
33
|
-
)
|
34
|
-
|
35
|
-
config = config1.merge(config2)
|
36
|
-
|
37
|
-
assert_equal(
|
38
|
-
{ config2_global: "config2:config2_global" },
|
39
|
-
config.globals
|
40
|
-
)
|
41
|
-
end
|
42
|
-
|
43
|
-
def test_merge_globals_in_config1_and_config2
|
44
|
-
config1 = ActiveRecordDoctor::Config.new(
|
45
|
-
{
|
46
|
-
config1_global: "config1:config1_global",
|
47
|
-
shared_global: "config1:shared_global"
|
48
|
-
},
|
49
|
-
{}
|
50
|
-
)
|
51
|
-
config2 = ActiveRecordDoctor::Config.new(
|
52
|
-
{
|
53
|
-
config2_global: "config2:config2_global",
|
54
|
-
shared_global: "config2:shared_global"
|
55
|
-
},
|
56
|
-
{}
|
57
|
-
)
|
58
|
-
|
59
|
-
config = config1.merge(config2)
|
60
|
-
|
61
|
-
assert_equal(
|
62
|
-
{
|
63
|
-
config1_global: "config1:config1_global",
|
64
|
-
shared_global: "config2:shared_global",
|
65
|
-
config2_global: "config2:config2_global"
|
66
|
-
},
|
67
|
-
config.globals
|
68
|
-
)
|
69
|
-
end
|
70
|
-
|
71
|
-
def test_merge_detectors
|
72
|
-
config1 = ActiveRecordDoctor::Config.new(
|
73
|
-
{},
|
74
|
-
{
|
75
|
-
config1_detector: {
|
76
|
-
config1_setting: "config1:config1_detector.config1_setting"
|
77
|
-
},
|
78
|
-
shared_detector: {
|
79
|
-
config1_setting: "config1:shared_detector.config1_setting",
|
80
|
-
shared_setting: "config1:shared_detector.shared_setting"
|
81
|
-
}
|
82
|
-
}
|
83
|
-
)
|
84
|
-
config2 = ActiveRecordDoctor::Config.new(
|
85
|
-
{},
|
86
|
-
{
|
87
|
-
config2_detector: {
|
88
|
-
config2_setting: "config2:config2_detector.config2_setting"
|
89
|
-
},
|
90
|
-
shared_detector: {
|
91
|
-
config2_setting: "config2:shared_detector.config2_setting",
|
92
|
-
shared_setting: "config2:shared_detector.shared_setting"
|
93
|
-
}
|
94
|
-
}
|
95
|
-
)
|
96
|
-
|
97
|
-
config = config1.merge(config2)
|
98
|
-
|
99
|
-
assert_equal(
|
100
|
-
{
|
101
|
-
config1_detector: {
|
102
|
-
config1_setting: "config1:config1_detector.config1_setting"
|
103
|
-
},
|
104
|
-
config2_detector: {
|
105
|
-
config2_setting: "config2:config2_detector.config2_setting"
|
106
|
-
},
|
107
|
-
shared_detector: {
|
108
|
-
config1_setting: "config1:shared_detector.config1_setting",
|
109
|
-
config2_setting: "config2:shared_detector.config2_setting",
|
110
|
-
shared_setting: "config2:shared_detector.shared_setting"
|
111
|
-
}
|
112
|
-
},
|
113
|
-
config.detectors
|
114
|
-
)
|
115
|
-
end
|
116
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class ActiveRecordDoctor::Detectors::DisableTest < Minitest::Test
|
4
|
-
# Disabling detectors is implemented in the base class. It's enought to test
|
5
|
-
# it on a single detector to be reasonably certain it works on all of them.
|
6
|
-
def test_disabling
|
7
|
-
create_table(:users) do |t|
|
8
|
-
t.string :name, null: true
|
9
|
-
end.define_model do
|
10
|
-
validates :name, presence: true
|
11
|
-
end
|
12
|
-
|
13
|
-
config_file(<<-CONFIG)
|
14
|
-
ActiveRecordDoctor.configure do |config|
|
15
|
-
config.detector :missing_non_null_constraint,
|
16
|
-
enabled: false
|
17
|
-
end
|
18
|
-
CONFIG
|
19
|
-
|
20
|
-
refute_problems
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
# We need to override that method in order to skip the mechanism that
|
26
|
-
# infers detector name from the test class name.
|
27
|
-
def detector_name
|
28
|
-
:missing_non_null_constraint
|
29
|
-
end
|
30
|
-
end
|