consistency_fail 0.3.3 → 0.3.4

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.
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
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- NTdkY2IwZWQ2ZjI5Mzk1ZDc3NTMxNzFhM2IyNDllZWVhMmUwZWQ4OQ==
5
- data.tar.gz: !binary |-
6
- YzQzNDRjODdhN2RhN2UzZmVhMjIwYzkxMDQ5NTY3NjEyMDM2NWM5Mw==
2
+ SHA1:
3
+ metadata.gz: e39eaf9c01eac716941d478876cccf815cac17df
4
+ data.tar.gz: ea14788fa3224a69441d52803d69992d910b360c
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- OGVlNzc3MTFlMDEyNzk5YmViM2UwOTI4YzAzNGMwY2U0Y2M4MGQ0MjRmMTM4
10
- ZDgwZGM1YmE1MjhlMzA1MzVlZDU2YzJlNGJmNmQ2ZjMxNWQ0YzE4OTY5YjEx
11
- Y2ZiNWFjMThkODRjMGNiMzY4ZjYwNDFjMzU0Yzk3MDBiNTViZWM=
12
- data.tar.gz: !binary |-
13
- MzJmNWE4YTU4MWRjMTExMDYwN2JkNGQyYzBhMWNiOWRjNGY3ZmJlYjg5MzQ0
14
- NzBlNDY3N2I2OWJiMWU1OWEzNDFkYzliZDkzYzcwZDA1ZmY4ZWUzOTBhODky
15
- NzI4NTA5OWM0YjY3ZDYyNmNhMmVjMjM4N2U4MWRmY2VjNzlmMzc=
6
+ metadata.gz: c60df52fb547fc080706b1e38f550fc26fd4aacf9cfbae471f8d39cebce76e9f03df7b782df0df7fe13ab5496d27650d526a815e481786900dc0c523d8802aa6
7
+ data.tar.gz: d999a4beba6dddf954b7f5c670c117222b42247a64e92015bd4bae13ebc648df82988a49294eaac5bca22992a4b9daa719b98e997d06738c106b258a462cb35a
data/.rspec CHANGED
@@ -1 +1,2 @@
1
1
  --color
2
+ --require spec_helper
@@ -13,37 +13,7 @@ require File.join(Dir.pwd, "config", "environment")
13
13
  $:<< File.join(File.dirname(__FILE__), "..", "lib")
14
14
  require "consistency_fail"
15
15
 
16
- def problems(models, introspector)
17
- models.map do |m|
18
- [m, introspector.missing_indexes(m)]
19
- end.reject do |m, indexes|
20
- indexes.empty?
21
- end
22
- end
23
-
24
- models = ConsistencyFail::Models.new($LOAD_PATH)
25
- models.preload_all
26
-
27
- reporter = ConsistencyFail::Reporter.new
28
-
29
- success = true
30
-
31
- introspector = ConsistencyFail::Introspectors::ValidatesUniquenessOf.new
32
- problems = problems(models.all, introspector)
33
- reporter.report_validates_uniqueness_problems(problems)
34
- success &&= problems.empty?
35
-
36
- introspector = ConsistencyFail::Introspectors::HasOne.new
37
- problems = problems(models.all, introspector)
38
- reporter.report_has_one_problems(problems)
39
- success &&= problems.empty?
40
-
41
- introspector = ConsistencyFail::Introspectors::Polymorphic.new
42
- problems = problems(models.all, introspector)
43
- reporter.report_polymorphic_problems(problems)
44
- success &&= problems.empty?
45
-
46
- if success
16
+ if ConsistencyFail.run
47
17
  exit 0
48
18
  else
49
19
  exit 1
@@ -22,7 +22,8 @@ EOF
22
22
  s.license = "MIT"
23
23
 
24
24
  s.add_development_dependency "activerecord", "~>3.0"
25
- s.add_development_dependency "rspec", "~>3.1"
25
+ s.add_development_dependency "sqlite3", "~>1.3"
26
+ s.add_development_dependency "rspec", "~>3.2"
26
27
 
27
28
  s.files = `git ls-files`.split("\n")
28
29
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -4,3 +4,41 @@ require 'consistency_fail/introspectors/validates_uniqueness_of'
4
4
  require 'consistency_fail/introspectors/has_one'
5
5
  require 'consistency_fail/introspectors/polymorphic'
6
6
  require 'consistency_fail/reporter'
7
+
8
+ module ConsistencyFail
9
+ def self.run
10
+ models = ConsistencyFail::Models.new($LOAD_PATH)
11
+ models.preload_all
12
+
13
+ reporter = ConsistencyFail::Reporter.new
14
+
15
+ success = true
16
+
17
+ introspector = ConsistencyFail::Introspectors::ValidatesUniquenessOf.new
18
+ problems = problems(models.all, introspector)
19
+ reporter.report_validates_uniqueness_problems(problems)
20
+ success &&= problems.empty?
21
+
22
+ introspector = ConsistencyFail::Introspectors::HasOne.new
23
+ problems = problems(models.all, introspector)
24
+ reporter.report_has_one_problems(problems)
25
+ success &&= problems.empty?
26
+
27
+ introspector = ConsistencyFail::Introspectors::Polymorphic.new
28
+ problems = problems(models.all, introspector)
29
+ reporter.report_polymorphic_problems(problems)
30
+ success &&= problems.empty?
31
+
32
+ success
33
+ end
34
+
35
+ private
36
+
37
+ def self.problems(models, introspector)
38
+ models.map do |m|
39
+ [m, introspector.missing_indexes(m)]
40
+ end.reject do |m, indexes|
41
+ indexes.empty?
42
+ end
43
+ end
44
+ end
@@ -5,11 +5,29 @@ module ConsistencyFail
5
5
  @model = model
6
6
  @table_name = table_name
7
7
  @columns = columns.map(&:to_s)
8
+ handle_associations
8
9
  end
9
10
 
10
11
  def ==(other)
11
12
  self.table_name == other.table_name &&
12
13
  self.columns.sort == other.columns.sort
13
14
  end
15
+
16
+ private
17
+
18
+ def handle_associations
19
+ references = @model.reflect_on_all_associations(:belongs_to)
20
+ names = references.map(&:name).map(&:to_s)
21
+ @columns.map! do |column|
22
+ next column unless names.include?(column)
23
+ reflection = @model.reflect_on_association(column.to_sym)
24
+ if reflection.options[:polymorphic]
25
+ [reflection.foreign_key, reflection.foreign_type]
26
+ else
27
+ reflection.foreign_key
28
+ end
29
+ end
30
+ @columns.flatten!
31
+ end
14
32
  end
15
33
  end
@@ -17,7 +17,7 @@ module ConsistencyFail
17
17
  else
18
18
  foreign_key = a.primary_key_name
19
19
  end
20
- ConsistencyFail::Index.new(a.class_name.constantize,
20
+ ConsistencyFail::Index.new(a.klass,
21
21
  a.table_name.to_s,
22
22
  [foreign_key])
23
23
  end.compact
@@ -16,7 +16,7 @@ module ConsistencyFail
16
16
  as_id = "#{as}_id"
17
17
 
18
18
  ConsistencyFail::Index.new(
19
- a.class_name.constantize,
19
+ a.klass,
20
20
  a.table_name.to_s,
21
21
  [as_type, as_id]
22
22
  )
@@ -37,7 +37,6 @@ module ConsistencyFail
37
37
  existing_indexes.include?(index)
38
38
  end
39
39
  end
40
-
41
40
  end
42
41
  end
43
42
  end
@@ -22,6 +22,7 @@ module ConsistencyFail
22
22
  private :desired_indexes
23
23
 
24
24
  def missing_indexes(model)
25
+ return [] unless model.connection.tables.include? model.table_name
25
26
  existing_indexes = TableData.new.unique_indexes(model)
26
27
 
27
28
  desired_indexes(model).reject do |index|
@@ -26,6 +26,5 @@ module ConsistencyFail
26
26
  def all
27
27
  ActiveRecord::Base.send(:descendants).sort_by(&:name)
28
28
  end
29
-
30
29
  end
31
30
  end
@@ -1,3 +1,3 @@
1
1
  module ConsistencyFail
2
- VERSION = "0.3.3"
2
+ VERSION = "0.3.4"
3
3
  end
@@ -1,40 +1,59 @@
1
- require 'spec_helper'
2
- require 'consistency_fail/index'
3
-
4
1
  describe ConsistencyFail::Index do
5
-
2
+
3
+ let(:index) do
4
+ ConsistencyFail::Index.new(
5
+ CorrectAddress,
6
+ CorrectAddress.table_name,
7
+ ["city", "state"]
8
+ )
9
+ end
10
+
6
11
  describe "value objectiness" do
7
12
  it "holds onto model, table name, and columns" do
8
- model = double("model")
9
- index = ConsistencyFail::Index.new(model, "addresses", ["city", "state"])
10
- expect(index.model).to eq(model)
11
- expect(index.table_name).to eq("addresses")
12
- expect(index.columns).to eq(["city", "state"])
13
+ expect(index.model).to eq(CorrectAddress)
14
+ expect(index.table_name).to eq("correct_addresses")
15
+ expect(index.columns).to eq(
16
+ ["city", "state"]
17
+ )
13
18
  end
14
19
 
15
20
  it "leaves columns in the initial order (since we only care about presence, not performance)" do
16
- index = ConsistencyFail::Index.new(double('model'), "addresses", ["state", "city"])
17
- expect(index.columns).to eq(["state", "city"])
21
+ expect(index.columns).to eq(
22
+ ["city", "state"]
23
+ )
18
24
  end
19
25
  end
20
26
 
21
- describe "equality test" do
27
+ describe "equality test" do
22
28
  it "passes when everything matches" do
23
- expect(ConsistencyFail::Index.new(double('model'), "addresses", ["city", "state"])).to eq(
24
- ConsistencyFail::Index.new(double('model'),"addresses", ["city", "state"])
29
+ expect(index).to eq(
30
+ ConsistencyFail::Index.new(
31
+ "CorrectAddress".constantize,
32
+ "correct_addresses",
33
+ ["city", "state"]
34
+ )
25
35
  )
26
36
  end
27
37
 
28
38
  it "fails when tables are different" do
29
- expect(ConsistencyFail::Index.new(double('model'),"locations", ["city", "state"])).not_to eq(
30
- ConsistencyFail::Index.new(double('model'),"addresses", ["city", "state"])
39
+ expect(index).not_to eq(
40
+ ConsistencyFail::Index.new(
41
+ CorrectAttachment,
42
+ CorrectAttachment.table_name,
43
+ ["attachable_id", "attachable_type"]
44
+ )
31
45
  )
32
46
  end
33
47
 
34
48
  it "fails when columns are different" do
35
- expect(ConsistencyFail::Index.new(double('model'),"addresses", ["city", "state"])).not_to eq(
36
- ConsistencyFail::Index.new(double('model'),"addresses", ["state", "zip"])
49
+ expect(index).not_to eq(
50
+ ConsistencyFail::Index.new(
51
+ CorrectAddress,
52
+ CorrectAddress.table_name,
53
+ ["correct_user_id"]
54
+ )
37
55
  )
38
56
  end
39
57
  end
58
+
40
59
  end
@@ -1,96 +1,21 @@
1
- require 'spec_helper'
2
- require 'consistency_fail/introspectors/table_data'
3
- require 'consistency_fail/introspectors/has_one'
4
-
5
1
  describe ConsistencyFail::Introspectors::HasOne do
6
- def introspector(model)
7
- ConsistencyFail::Introspectors::HasOne.new(model)
8
- end
9
-
10
- describe "instances of has_one" do
11
- it "finds none" do
12
- model = fake_ar_model("User")
13
- allow(model).to receive(:reflect_on_all_associations).and_return([])
14
-
15
- expect(subject.instances(model)).to eq([])
16
- end
17
-
18
- it "finds one" do
19
- model = fake_ar_model("User")
20
- association = double("association", :macro => :has_one, :options => {})
21
- allow(model).to receive(:reflect_on_all_associations).and_return([association])
22
-
23
- expect(subject.instances(model)).to eq([association])
24
- end
25
-
26
- it "finds other associations, but not has_one" do
27
- model = fake_ar_model("User")
28
- validation = double("validation", :macro => :has_many)
29
- allow(model).to receive(:reflect_on_all_associations).and_return([validation])
30
-
31
- expect(subject.instances(model)).to eq([])
32
- end
33
-
34
- it "finds one, but it's a polymorphic association" do
35
- model = fake_ar_model("User")
36
- association = double("association", :macro => :has_one, :options => {:as => "addressable"})
37
- allow(model).to receive(:reflect_on_all_associations).and_return([association])
38
-
39
- expect(subject.instances(model)).to eq([])
40
- end
41
-
42
- it "finds one, but it's a :through association" do
43
- model = fake_ar_model("User")
44
- association = double("association", :macro => :has_one, :options => {:through => :amodel})
45
- allow(model).to receive(:reflect_on_all_associations).and_return([association])
46
-
47
- expect(subject.instances(model)).to eq([])
48
- end
49
- end
50
-
2
+
51
3
  describe "finding missing indexes" do
52
- before do
53
- @association = double("association", :macro => :has_one, :options => {})
54
- @model = fake_ar_model("User", :table_exists? => true,
55
- :table_name => "users",
56
- :class_name => "User",
57
- :reflect_on_all_associations => [@association])
58
- @address_class = double("Address Class")
59
- @address_string = "Address"
60
- allow(@address_string).to receive(:constantize).and_return(@address_class)
61
- end
62
-
63
4
  it "finds one" do
64
- allow(@association).to receive_messages(:table_name => :addresses, :class_name => @address_string, :foreign_key => "user_id")
65
- allow(@address_class).to receive_message_chain(:connection, :indexes).with("addresses").and_return([])
66
-
67
- indexes = subject.missing_indexes(@model)
68
- expect(indexes).to eq([ConsistencyFail::Index.new(fake_ar_model("Address"), "addresses", ["user_id"])])
69
- end
70
-
71
- it "finds one in Rails 3.0.x (where foreign_key is not defined)" do
72
- allow(@association).to receive_messages(:table_name => :addresses, :class_name => @address_string, :primary_key_name => "user_id")
73
- allow(@address_class).to receive_message_chain(:connection, :indexes).with("addresses").and_return([])
74
-
75
- indexes = subject.missing_indexes(@model)
76
- expect(indexes).to eq([ConsistencyFail::Index.new(fake_ar_model("Address"), "addresses", ["user_id"])])
77
- end
78
-
5
+ indexes = subject.missing_indexes(WrongUser)
6
+
7
+ expect(indexes).to eq([
8
+ ConsistencyFail::Index.new(
9
+ WrongAddress,
10
+ WrongAddress.table_name,
11
+ ["wrong_user_id"]
12
+ )
13
+ ])
14
+ end
15
+
79
16
  it "finds none when they're already in place" do
80
- allow(@association).to receive_messages(:table_name => :addresses, :class_name => @address_string, :foreign_key => "user_id")
81
- index = ConsistencyFail::Index.new(double('model'), "addresses", ["user_id"])
82
-
83
- fake_connection = double("connection")
84
- allow(@address_class).to receive_message_chain(:connection).and_return(fake_connection)
85
-
86
- allow(ConsistencyFail::Introspectors::TableData).to receive_message_chain(:new, :unique_indexes_by_table).
87
- with(@address_class, fake_connection, "addresses").
88
- and_return([index])
89
-
90
- expect(subject.missing_indexes(@model)).to eq([])
17
+ expect(subject.missing_indexes(CorrectUser)).to be_empty
91
18
  end
92
-
93
19
  end
20
+
94
21
  end
95
-
96
-
@@ -1,77 +1,26 @@
1
- require 'spec_helper'
2
- require 'consistency_fail/introspectors/table_data'
3
- require 'consistency_fail/introspectors/polymorphic'
4
-
5
1
  describe ConsistencyFail::Introspectors::Polymorphic do
6
- def introspector(model)
7
- ConsistencyFail::Introspectors::Polymorphic.new(model)
8
- end
9
-
10
- describe "instances of polymorphic" do
11
- it "finds none" do
12
- model = fake_ar_model("User")
13
- allow(model).to receive(:reflect_on_all_associations).and_return([])
14
-
15
- expect(subject.instances(model)).to eq([])
16
- end
17
-
18
- it "finds one" do
19
- model = fake_ar_model("User")
20
- association = double("association", :macro => :has_one, :options => {:as => "addressable"})
21
- allow(model).to receive(:reflect_on_all_associations).and_return([association])
22
-
23
- expect(subject.instances(model)).to eq([association])
24
- end
25
-
26
- it "finds other has_one associations, but not polymorphic" do
27
- model = fake_ar_model("User")
28
- validation = double("association", :macro => :has_one, :options => {})
29
- allow(model).to receive(:reflect_on_all_associations).and_return([validation])
30
-
31
- expect(subject.instances(model)).to eq([])
32
- end
33
-
34
- it "finds other non has_one associations" do
35
- model = fake_ar_model("User")
36
- validation = double("association", :macro => :has_many)
37
- allow(model).to receive(:reflect_on_all_associations).and_return([validation])
38
-
39
- expect(subject.instances(model)).to eq([])
40
- end
41
- end
42
2
 
43
3
  describe "finding missing indexes" do
44
- before do
45
- @association = double("association", :macro => :has_one, :options => {:as => "addressable"})
46
- @model = fake_ar_model("User", :table_exists? => true,
47
- :table_name => "users",
48
- :class_name => "User",
49
- :reflect_on_all_associations => [@association])
50
- @address_class = double("Address Class")
51
- @address_string = "Address"
52
- allow(@address_string).to receive(:constantize).and_return(@address_class)
53
- end
54
-
55
4
  it "finds one" do
56
- allow(@association).to receive_messages(:table_name => :addresses, :class_name => @address_string)
57
- allow(@address_class).to receive_message_chain(:connection, :indexes).with("addresses").and_return([])
58
-
59
- indexes = subject.missing_indexes(@model)
60
- expect(indexes).to eq([ConsistencyFail::Index.new(fake_ar_model("Address"), "addresses", ["addressable_type", "addressable_id"])])
5
+ indexes = subject.missing_indexes(WrongPost)
6
+
7
+ expect(indexes).to eq([
8
+ ConsistencyFail::Index.new(
9
+ WrongAttachment,
10
+ WrongAttachment.table_name,
11
+ ["attachable_type", "attachable_id"]
12
+ )
13
+ ])
61
14
  end
62
15
 
63
16
  it "finds none when they're already in place" do
64
- allow(@association).to receive_messages(:table_name => :addresses, :class_name => @address_string)
65
- index = ConsistencyFail::Index.new(double('model'), "addresses", ["addressable_type", "addressable_id"])
66
-
67
- fake_connection = double("connection")
68
- allow(@address_class).to receive_message_chain(:connection).and_return(fake_connection)
69
-
70
- allow(ConsistencyFail::Introspectors::TableData).to receive_message_chain(:new, :unique_indexes_by_table).
71
- with(@address_class, fake_connection, "addresses").
72
- and_return([index])
17
+ expect(subject.missing_indexes(CorrectPost)).to be_empty
18
+ end
73
19
 
74
- expect(subject.missing_indexes(@model)).to eq([])
20
+ it "finds none with nested modules" do
21
+ expect(subject.missing_indexes(CorrectUser)).to eq([])
75
22
  end
23
+
76
24
  end
25
+
77
26
  end