consistency_fail 0.3.3 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +5 -13
  2. data/.rspec +1 -0
  3. data/bin/consistency_fail +1 -31
  4. data/consistency_fail.gemspec +2 -1
  5. data/lib/consistency_fail.rb +38 -0
  6. data/lib/consistency_fail/index.rb +18 -0
  7. data/lib/consistency_fail/introspectors/has_one.rb +1 -1
  8. data/lib/consistency_fail/introspectors/polymorphic.rb +1 -2
  9. data/lib/consistency_fail/introspectors/validates_uniqueness_of.rb +1 -0
  10. data/lib/consistency_fail/models.rb +0 -1
  11. data/lib/consistency_fail/version.rb +1 -1
  12. data/spec/index_spec.rb +37 -18
  13. data/spec/introspectors/has_one_spec.rb +14 -89
  14. data/spec/introspectors/polymorphic_spec.rb +15 -66
  15. data/spec/introspectors/table_data_spec.rb +47 -36
  16. data/spec/introspectors/validates_uniqueness_of_spec.rb +47 -72
  17. data/spec/models_spec.rb +2 -3
  18. data/spec/reporter_spec.rb +88 -49
  19. data/spec/spec_helper.rb +11 -10
  20. data/spec/support/active_record.rb +1 -0
  21. data/spec/support/models/correct_account.rb +3 -0
  22. data/spec/support/models/correct_address.rb +3 -0
  23. data/spec/support/models/correct_attachment.rb +5 -0
  24. data/spec/support/models/correct_person.rb +3 -0
  25. data/spec/support/models/correct_post.rb +3 -0
  26. data/spec/support/models/correct_user.rb +7 -0
  27. data/spec/support/models/correct_user/credential.rb +3 -0
  28. data/spec/support/models/correct_user/phone.rb +4 -0
  29. data/spec/support/models/new_correct_person.rb +7 -0
  30. data/spec/support/models/nonexistent.rb +2 -0
  31. data/spec/support/models/wrong_account.rb +3 -0
  32. data/spec/support/models/wrong_address.rb +5 -0
  33. data/spec/support/models/wrong_attachment.rb +3 -0
  34. data/spec/support/models/wrong_business.rb +3 -0
  35. data/spec/support/models/wrong_person.rb +3 -0
  36. data/spec/support/models/wrong_post.rb +3 -0
  37. data/spec/support/models/wrong_user.rb +3 -0
  38. data/spec/support/schema.rb +121 -0
  39. metadata +68 -24
@@ -1,52 +1,63 @@
1
- require 'spec_helper'
2
- require 'consistency_fail/introspectors/table_data'
3
-
4
1
  describe ConsistencyFail::Introspectors::TableData do
2
+
5
3
  describe "finding unique indexes" do
6
4
  it "finds none when the table does not exist" do
7
- model = fake_ar_model("User", :table_exists? => false)
8
-
9
- expect(subject.unique_indexes(model)).to eq([])
5
+ expect(subject.unique_indexes(Nonexistent)).to be_empty
10
6
  end
11
7
 
12
8
  it "gets one" do
13
- model = fake_ar_model("User", :table_exists? => true,
14
- :table_name => "users")
15
-
16
- allow(model).to receive_message_chain(:connection, :indexes).
17
- with("users").
18
- and_return([fake_index_on(["a"], :unique => true)])
19
-
20
- indexes = subject.unique_indexes(model)
21
- expect(indexes).to eq([ConsistencyFail::Index.new(double('model'), "users", ["a"])])
9
+ index = ConsistencyFail::Index.new(
10
+ CorrectAccount,
11
+ CorrectAccount.table_name,
12
+ ["email"]
13
+ )
14
+
15
+ expect(
16
+ ConsistencyFail::Introspectors::TableData.new.unique_indexes_by_table(
17
+ CorrectAccount,
18
+ ActiveRecord::Base.connection,
19
+ CorrectAccount.table_name
20
+ )
21
+ ).to eq [index]
22
22
  end
23
23
 
24
24
  it "doesn't get non-unique indexes" do
25
- model = fake_ar_model("User", :table_exists? => true,
26
- :table_name => "users")
27
-
28
- allow(model).to receive_message_chain(:connection, :indexes).
29
- with("users").
30
- and_return([fake_index_on(["a"], :unique => false)])
31
-
32
- expect(subject.unique_indexes(model)).to eq([])
25
+ expect(
26
+ ConsistencyFail::Introspectors::TableData.new.unique_indexes_by_table(
27
+ WrongAddress,
28
+ ActiveRecord::Base.connection,
29
+ WrongAddress.table_name
30
+ )
31
+ ).to be_empty
33
32
  end
34
33
 
35
34
  it "gets multiple unique indexes" do
36
- model = fake_ar_model("User", :table_exists? => true,
37
- :table_name => "users")
38
-
39
- allow(model).to receive_message_chain(:connection, :indexes).
40
- with("users").
41
- and_return([fake_index_on(["a"], :unique => true),
42
- fake_index_on(["b", "c"], :unique => true)])
43
-
44
- indexes = subject.unique_indexes(model)
45
- expect(indexes.size).to eq(2)
46
- expect(indexes).to eq([ConsistencyFail::Index.new(double('model'), "users", ["a"]),
47
- ConsistencyFail::Index.new(double('model'), "users", ["b", "c"])])
35
+ indexes = [
36
+ ConsistencyFail::Index.new(
37
+ CorrectAttachment,
38
+ CorrectAttachment.table_name,
39
+ ["name"]
40
+ ),
41
+ ConsistencyFail::Index.new(
42
+ CorrectAttachment,
43
+ CorrectAttachment.table_name,
44
+ ["attachable_id", "attachable_type"]
45
+ ),
46
+ ConsistencyFail::Index.new(
47
+ CorrectAttachment,
48
+ CorrectAttachment.table_name,
49
+ ["name", "attachable_id", "attachable_type"]
50
+ )
51
+ ]
52
+
53
+ expect(
54
+ ConsistencyFail::Introspectors::TableData.new.unique_indexes_by_table(
55
+ CorrectAttachment,
56
+ ActiveRecord::Base.connection,
57
+ CorrectAttachment.table_name
58
+ )
59
+ ).to eq indexes
48
60
  end
49
61
  end
50
62
 
51
63
  end
52
-
@@ -1,93 +1,68 @@
1
- require 'spec_helper'
2
- require 'consistency_fail/introspectors/validates_uniqueness_of'
3
-
4
1
  describe ConsistencyFail::Introspectors::ValidatesUniquenessOf do
5
- def introspector(model)
6
- ConsistencyFail::Introspectors::ValidatesUniquenessOf.new(model)
7
- end
8
-
9
- describe "instances of validates_uniqueness_of" do
10
- it "finds none" do
11
- model = fake_ar_model("User")
12
- allow(model).to receive(:validators).and_return([])
13
-
14
- expect(subject.instances(model)).to eq([])
15
- end
16
-
17
- it "finds one" do
18
- model = fake_ar_model("User")
19
- validation = double("validation", :class => ActiveRecord::Validations::UniquenessValidator)
20
- allow(model).to receive(:validators).and_return([validation])
21
-
22
- expect(subject.instances(model)).to eq([validation])
23
- end
24
-
25
- it "finds other validations, but not uniqueness" do
26
- model = fake_ar_model("User")
27
- validation = double("validation", :class => ActiveModel::Validations::FormatValidator)
28
- allow(model).to receive(:validators).and_return([validation])
29
-
30
- expect(subject.instances(model)).to eq([])
31
- end
32
- end
33
2
 
34
3
  describe "finding missing indexes" do
35
- before do
36
- @validation = double("validation", :class => ActiveRecord::Validations::UniquenessValidator)
37
- @model = fake_ar_model("User", :table_exists? => true,
38
- :table_name => "users",
39
- :validators => [@validation])
40
- end
41
-
42
4
  it "finds one" do
43
- allow(@validation).to receive_messages(:attributes => [:email], :options => {})
44
- allow(@model).to receive_message_chain(:connection, :indexes).with("users").and_return([])
45
-
46
- indexes = subject.missing_indexes(@model)
47
- expect(indexes).to eq([ConsistencyFail::Index.new(double('model'), "users", ["email"])])
5
+ indexes = subject.missing_indexes(WrongAccount)
6
+
7
+ expect(indexes).to eq([
8
+ ConsistencyFail::Index.new(
9
+ WrongAccount,
10
+ WrongAccount.table_name,
11
+ ["email"]
12
+ )
13
+ ])
48
14
  end
49
15
 
50
16
  it "finds one where the validation has scoped columns" do
51
- allow(@validation).to receive_messages(:attributes => [:city], :options => {:scope => [:email, :state]})
52
- allow(@model).to receive_message_chain(:connection, :indexes).with("users").and_return([])
53
-
54
- indexes = subject.missing_indexes(@model)
55
- expect(indexes).to eq([ConsistencyFail::Index.new(double('model'), "users", ["city", "email", "state"])])
56
- end
57
-
58
- it "leaves the columns in the given order" do
59
- allow(@validation).to receive_messages(:attributes => [:email], :options => {:scope => [:city, :state]})
60
- allow(@model).to receive_message_chain(:connection, :indexes).with("users").and_return([])
61
-
62
- indexes = subject.missing_indexes(@model)
63
- expect(indexes).to eq([ConsistencyFail::Index.new(double('model'), "users", ["email", "city", "state"])])
17
+ indexes = subject.missing_indexes(WrongBusiness)
18
+
19
+ expect(indexes).to eq([
20
+ ConsistencyFail::Index.new(
21
+ WrongBusiness,
22
+ WrongBusiness.table_name,
23
+ ["name", "city", "state"]
24
+ )
25
+ ])
64
26
  end
65
27
 
66
28
  it "finds two where there are multiple attributes" do
67
- allow(@validation).to receive_messages(:attributes => [:email, :name], :options => {:scope => [:city, :state]})
68
- allow(@model).to receive_message_chain(:connection, :indexes).with("users").and_return([])
69
-
70
- indexes = subject.missing_indexes(@model)
71
- expect(indexes).to eq([ConsistencyFail::Index.new(double('model'), "users", ["email", "city", "state"]),
72
- ConsistencyFail::Index.new(double('model'), "users", ["name", "city", "state"])])
29
+ indexes = subject.missing_indexes(WrongPerson)
30
+
31
+ expect(indexes).to eq(
32
+ [
33
+ ConsistencyFail::Index.new(
34
+ WrongPerson,
35
+ WrongPerson.table_name,
36
+ ["email", "city", "state"]
37
+ ),
38
+ ConsistencyFail::Index.new(
39
+ WrongPerson,
40
+ WrongPerson.table_name,
41
+ ["name", "city", "state"]
42
+ )
43
+ ]
44
+ )
73
45
  end
74
46
 
75
47
  it "finds none when they're already in place" do
76
- allow(@validation).to receive_messages(:attributes => [:email], :options => {})
77
- index = fake_index_on(["email"], :unique => true)
78
- allow(@model).to receive_message_chain(:connection, :indexes).with("users").
79
- and_return([index])
48
+ expect(subject.missing_indexes(CorrectAccount)).to be_empty
49
+ end
50
+
51
+ it "finds none even if scoped by association" do
52
+ expect(subject.missing_indexes(CorrectAddress)).to be_empty
53
+ end
80
54
 
81
- expect(subject.missing_indexes(@model)).to eq([])
55
+ it "finds none even if scoped by polymorphic association" do
56
+ expect(subject.missing_indexes(CorrectAttachment)).to be_empty
82
57
  end
83
58
 
84
59
  it "finds none when indexes are there but in a different order" do
85
- allow(@validation).to receive_messages(:attributes => [:email], :options => {:scope => [:city, :state]})
86
- index = fake_index_on(["state", "email", "city"], :unique => true)
87
- allow(@model).to receive_message_chain(:connection, :indexes).with("users").
88
- and_return([index])
60
+ expect(subject.missing_indexes(CorrectPerson)).to be_empty
61
+ end
89
62
 
90
- expect(subject.missing_indexes(@model)).to eq([])
63
+ it "finds none when the model is an SQL view" do
64
+ expect(subject.missing_indexes(NewCorrectPerson)).to be_empty
91
65
  end
92
66
  end
67
+
93
68
  end
@@ -1,7 +1,5 @@
1
- require 'spec_helper'
2
- require 'consistency_fail/models'
3
-
4
1
  describe ConsistencyFail::Models do
2
+
5
3
  def models(load_path)
6
4
  ConsistencyFail::Models.new(load_path)
7
5
  end
@@ -46,4 +44,5 @@ describe ConsistencyFail::Models do
46
44
 
47
45
  expect(models([]).all).to eq([model_a, model_c, model_b])
48
46
  end
47
+
49
48
  end
@@ -1,90 +1,129 @@
1
- require 'spec_helper'
2
- require 'consistency_fail/reporter'
3
- require 'consistency_fail/index'
4
-
5
1
  describe ConsistencyFail::Reporter do
6
- before(:each) do
7
- @real_out = $stdout
8
- @fake_out = StringIO.new
9
- $stdout = @fake_out
10
- end
11
- after(:each) do
12
- $stdout = @real_out
13
- end
14
-
2
+
15
3
  context "validates_uniqueness_of" do
16
4
  it "says everything's good" do
17
- subject.report_validates_uniqueness_problems([])
18
-
19
- expect(@fake_out.string).to match(/Hooray!/)
5
+ expect {
6
+ subject.report_validates_uniqueness_problems([])
7
+ }.to output(/Hooray!/).to_stdout
20
8
  end
21
9
 
22
10
  it "shows a missing single-column index on a single model" do
23
- missing_indexes = [ConsistencyFail::Index.new(double('model'), "users", ["email"])]
24
-
25
- subject.report_validates_uniqueness_problems(fake_ar_model("User", :table_name => "users") => missing_indexes)
11
+ missing_indexes = [
12
+ ConsistencyFail::Index.new(
13
+ WrongAccount,
14
+ WrongAccount.table_name,
15
+ ["email"]
16
+ )
17
+ ]
26
18
 
27
- expect(@fake_out.string).to match(/users\s+\(email\)/)
19
+ expect {
20
+ subject.report_validates_uniqueness_problems(
21
+ WrongAccount => missing_indexes
22
+ )
23
+ }.to output(/wrong_accounts\s+\(email\)/).to_stdout
28
24
  end
29
25
 
30
26
  it "shows a missing multiple-column index on a single model" do
31
- missing_indexes = [ConsistencyFail::Index.new(double('model'),"addresses", ["number", "street", "zip"])]
32
-
33
- subject.report_validates_uniqueness_problems(fake_ar_model("Address", :table_name => "addresses") => missing_indexes)
27
+ missing_indexes = [
28
+ ConsistencyFail::Index.new(
29
+ WrongBusiness,
30
+ WrongBusiness.table_name,
31
+ ["name", "city", "state"]
32
+ )
33
+ ]
34
34
 
35
- expect(@fake_out.string).to match(/addresses\s+\(number, street, zip\)/)
35
+ expect {
36
+ subject.report_validates_uniqueness_problems(
37
+ WrongBusiness => missing_indexes
38
+ )
39
+ }.to output(/wrong_businesses\s+\(name, city, state\)/).to_stdout
36
40
  end
37
41
 
38
42
  context "with problems on multiple models" do
39
- before(:each) do
40
- subject.report_validates_uniqueness_problems(
41
- fake_ar_model("User", :table_name => "users") =>
42
- [ConsistencyFail::Index.new(double('model'),"users", ["email"])],
43
- fake_ar_model("Citizen", :table_name => "citizens") =>
44
- [ConsistencyFail::Index.new(double('model'),"citizens", ["ssn"])]
45
- )
43
+ def report
44
+ missing_indices = {
45
+ WrongAccount => [
46
+ ConsistencyFail::Index.new(
47
+ WrongAccount,
48
+ WrongAccount.table_name,
49
+ ["email"]
50
+ )
51
+ ],
52
+ WrongBusiness => [
53
+ ConsistencyFail::Index.new(
54
+ WrongBusiness,
55
+ WrongBusiness.table_name,
56
+ ["name", "city", "state"]
57
+ )
58
+ ]
59
+ }
60
+
61
+ subject.report_validates_uniqueness_problems(missing_indices)
46
62
  end
47
63
 
48
64
  it "shows all problems" do
49
- expect(@fake_out.string).to match(/users\s+\(email\)/m)
50
- expect(@fake_out.string).to match(/citizens\s+\(ssn\)/m)
65
+ expect { report }.to output(/wrong_accounts\s+\(email\)/).to_stdout
66
+ expect { report }.to output(
67
+ /wrong_businesses\s+\(name, city, state\)/
68
+ ).to_stdout
51
69
  end
52
70
 
53
71
  it "orders the models alphabetically" do
54
- expect(@fake_out.string).to match(/citizens\s+\(ssn\).*users\s+\(email\)/m)
72
+ expect { report }.to output(/
73
+ wrong_accounts\s+\(email\)
74
+ (\s|\S)*
75
+ wrong_businesses\s+\(name,\scity,\sstate\)
76
+ /x).to_stdout
55
77
  end
56
78
  end
57
79
  end
58
80
 
59
81
  context "has_one" do
60
82
  it "says everything's good" do
61
- subject.report_has_one_problems([])
62
-
63
- expect(@fake_out.string).to match(/Hooray!/)
83
+ expect {
84
+ subject.report_has_one_problems([])
85
+ }.to output(/Hooray!/).to_stdout
64
86
  end
65
87
 
66
88
  it "shows a missing single-column index on a single model" do
67
- missing_indexes = [ConsistencyFail::Index.new(double('model'),"users", ["email"])]
68
-
69
- subject.report_has_one_problems(fake_ar_model("Friend", :table_name => "users") => missing_indexes)
89
+ missing_indexes = [
90
+ ConsistencyFail::Index.new(
91
+ WrongAddress,
92
+ WrongAddress.table_name,
93
+ ["wrong_user_id"]
94
+ )
95
+ ]
70
96
 
71
- expect(@fake_out.string).to match(/Friend\s+users\s+\(email\)/m)
97
+ expect {
98
+ subject.report_has_one_problems(WrongAddress => missing_indexes)
99
+ }.to output(/wrong_addresses\s+\(wrong_user_id\)/).to_stdout
72
100
  end
73
101
  end
74
102
 
75
103
  context "polymorphic" do
76
104
  it "says everything's good" do
77
- subject.report_polymorphic_problems([])
78
-
79
- expect(@fake_out.string).to match(/Hooray!/)
105
+ expect {
106
+ subject.report_polymorphic_problems([])
107
+ }.to output(/Hooray!/).to_stdout
80
108
  end
81
109
 
82
110
  it "shows a missing compound index on a single model" do
83
- missing_indexes = [ConsistencyFail::Index.new(double('model'), "addresses", ["addressable_type", "addressable_id"])]
84
-
85
- subject.report_polymorphic_problems(fake_ar_model("Address", :table_name => "addresses") => missing_indexes)
86
-
87
- expect(@fake_out.string).to match(/Address\s+addresses\s+\(addressable_type, addressable_id\)/m)
111
+ missing_indexes = [
112
+ ConsistencyFail::Index.new(
113
+ WrongAttachment,
114
+ WrongAttachment.table_name,
115
+ ["attachable_type", "attachable_id"]
116
+ )
117
+ ]
118
+
119
+ expect {
120
+ subject.report_polymorphic_problems(WrongAttachment => missing_indexes)
121
+ }.to(
122
+ output(
123
+ /wrong_attachments\s+\(attachable_type, attachable_id\)/
124
+ ).to_stdout
125
+ )
88
126
  end
89
127
  end
128
+
90
129
  end
@@ -1,13 +1,14 @@
1
- $:<< File.expand_path('..', __FILE__)
2
- $:<< File.expand_path('../../lib', __FILE__)
1
+ require 'bundler/setup'
3
2
 
4
- require 'rubygems'
3
+ Bundler.require(:default, :test)
5
4
 
6
- def fake_ar_model(name, options = {})
7
- double("AR model: #{name}", options.merge(:name => name))
8
- end
9
-
10
- def fake_index_on(columns, options = {})
11
- double("index on #{columns.inspect}", options.merge(:columns => columns))
12
- end
5
+ Dir['./spec/support/**/*.rb'].each { |file| require file }
13
6
 
7
+ RSpec.configure do |config|
8
+ config.around do |example|
9
+ ActiveRecord::Base.transaction do
10
+ example.run
11
+ raise ActiveRecord::Rollback
12
+ end
13
+ end
14
+ end