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
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