lifesaver 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/.rspec +1 -0
  2. data/.travis.yml +3 -1
  3. data/CHANGELOG.md +7 -0
  4. data/Gemfile +4 -0
  5. data/README.md +33 -13
  6. data/lib/lifesaver.rb +34 -11
  7. data/lib/lifesaver/config.rb +16 -0
  8. data/lib/lifesaver/index_worker.rb +10 -10
  9. data/lib/lifesaver/indexing/enqueuer.rb +37 -0
  10. data/lib/lifesaver/indexing/indexer.rb +40 -0
  11. data/lib/lifesaver/indexing/model_additions.rb +55 -0
  12. data/lib/lifesaver/notification/eager_loader.rb +48 -0
  13. data/lib/lifesaver/notification/enqueuer.rb +24 -0
  14. data/lib/lifesaver/notification/indexing_graph.rb +91 -0
  15. data/lib/lifesaver/notification/model_additions.rb +104 -0
  16. data/lib/lifesaver/notification/notifiable_associations.rb +49 -0
  17. data/lib/lifesaver/notification/traversal_queue.rb +48 -0
  18. data/lib/lifesaver/railtie.rb +4 -3
  19. data/lib/lifesaver/serialized_model.rb +3 -0
  20. data/lib/lifesaver/version.rb +1 -1
  21. data/lib/lifesaver/visitor_worker.rb +8 -4
  22. data/spec/integration/lifesaver_spec.rb +78 -0
  23. data/spec/spec_helper.rb +12 -10
  24. data/spec/support/active_record.rb +3 -3
  25. data/spec/support/test_models.rb +8 -6
  26. data/spec/support/tire_helper.rb +37 -0
  27. data/spec/unit/config_spec.rb +17 -0
  28. data/spec/unit/indexing/indexer_spec.rb +51 -0
  29. data/spec/unit/indexing/model_addtions_spec.rb +53 -0
  30. data/spec/unit/notification/eager_loader_spec.rb +64 -0
  31. data/spec/unit/notification/enqueuer_spec.rb +39 -0
  32. data/spec/unit/notification/indexing_graph_spec.rb +73 -0
  33. data/spec/unit/notification/model_additions_spec.rb +69 -0
  34. data/spec/unit/notification/notifiable_associations_spec.rb +75 -0
  35. data/spec/unit/notification/traversal_queue_spec.rb +67 -0
  36. metadata +40 -14
  37. data/lib/lifesaver/index_graph.rb +0 -53
  38. data/lib/lifesaver/marshal.rb +0 -43
  39. data/lib/lifesaver/model_additions.rb +0 -133
  40. data/spec/lifesaver/index_graph_spec.rb +0 -64
  41. data/spec/lifesaver/marshal_spec.rb +0 -80
  42. data/spec/lifesaver/model_additions_spec.rb +0 -91
  43. data/spec/lifesaver_spec.rb +0 -111
@@ -1,80 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Lifesaver::Marshal do
4
- describe ".is_serialized?" do
5
- it "returns true if Hash has :id and :class" do
6
- obj = { class: :post, id: 1 }
7
- expect(Lifesaver::Marshal.is_serialized?(obj)).to eql(true)
8
- end
9
-
10
- it "returns true if Hash has 'id' and 'class'" do
11
- obj = { "class" => "post", "id" => "1" }
12
- expect(Lifesaver::Marshal.is_serialized?(obj)).to eql(true)
13
- end
14
-
15
- it "returns false if Hash does not have id and class keys" do
16
- obj = { some_key: 1, id: 4 }
17
- expect(Lifesaver::Marshal.is_serialized?(obj)).to eql(false)
18
- end
19
-
20
- it "returns false if passed an non-Hash object" do
21
- obj = Post.new
22
- expect(Lifesaver::Marshal.is_serialized?(obj)).to eql(false)
23
- end
24
- end
25
-
26
- describe ".sanitize" do
27
- it "returns symbolized version of the Hash'" do
28
- obj = { "class" => "post", "id" => "1", "status" => "updated" }
29
- out = { class: :post, id: 1, status: :updated }
30
- expect(Lifesaver::Marshal.sanitize(obj)).to eql(out)
31
- end
32
-
33
- it "rejects non-Hashes" do
34
- obj = Post.new
35
- expect { Lifesaver::Marshal.sanitize(obj) }.to raise_error
36
- end
37
- end
38
-
39
- describe ".load" do
40
- before(:all) do
41
- Post.create(title: "Test Post")
42
- end
43
-
44
- it "loads a serialized object from ActiveRecord" do
45
- obj = { class: :post, id: 1 }
46
- expect(Lifesaver::Marshal.load(obj)).to eql([Post.find(1), {}])
47
- end
48
-
49
- it "returns nil if model not found" do
50
- obj = { class: :post, id: 12 }
51
- expect(Lifesaver::Marshal.load(obj)).to eql(nil)
52
- end
53
-
54
- it "returns options if they were passed" do
55
- obj = { class: :post, id: 1, status: :notified }
56
- m = Lifesaver::Marshal.load(obj)
57
- expect(m).to eql([Post.find(1), {status: :notified}])
58
- end
59
-
60
-
61
- it "rejects bad input" do
62
- obj = Post.new
63
- expect { Lifesaver::Marshal.load(obj) }.to raise_error
64
- end
65
- end
66
-
67
- describe ".dump" do
68
- it "decomposes an object to a Hash" do
69
- obj = Post.create(title: "Test Post")
70
- out = { class: :post, id: 2 }
71
- expect(Lifesaver::Marshal.dump(obj)).to eql(out)
72
- end
73
-
74
- it "adds additional key, value pairs if passed" do
75
- obj = Post.create(title: "Test Post")
76
- out = { status: :updated, class: :post, id: 2 }
77
- expect(Lifesaver::Marshal.dump(obj, {status: :updated})).to eql(out)
78
- end
79
- end
80
- end
@@ -1,91 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Lifesaver::ModelAdditions do
4
- Lifesaver.suppress_indexing
5
-
6
- describe ".notifies_for_indexing" do
7
- after(:each) do
8
- Post.send(:notifies_for_indexing, only_on_change: :authorships)
9
- end
10
- it "should return a Hash of models for notification on save and notify" do
11
- Post.send(:notifies_for_indexing, :comments,
12
- only_on_change: :authorships,
13
- only_on_notify: :authors
14
- )
15
- exp_hash = { on_change: [], on_notify: [] }
16
- exp_hash[:on_change] << :comments
17
- exp_hash[:on_change] << :authorships
18
- exp_hash[:on_notify] << :comments
19
- exp_hash[:on_notify] << :authors
20
- expect(Post.notifiable_associations).to eql(exp_hash)
21
- end
22
- end
23
-
24
- describe "#association_models" do
25
- before(:each) do
26
- @post = Post.create(title: "Some post")
27
- affiliate = Affiliate.create(name: "Some place")
28
- @author = Author.create(name: "Some guy", affiliate_id: affiliate.id)
29
- Authorship.create(post: @post, author: @author)
30
- end
31
- after(:all) do
32
- Post.destroy_all
33
- Author.destroy_all
34
- Authorship.destroy_all
35
- Affiliate.destroy_all
36
- end
37
-
38
- it "should return an array of models for multiple association" do
39
- association = @post.association_models(:authorships)
40
- expect(association[0]).to be_a_kind_of(Authorship)
41
- end
42
-
43
- it "should return an array of one model for a singular association" do
44
- association = @author.association_models(:affiliate)
45
- expect(association[0]).to be_a_kind_of(Affiliate)
46
- end
47
- end
48
-
49
- Lifesaver.unsuppress_indexing
50
-
51
- describe "#indexing_suppressed?" do
52
- let(:post) { Post.new(title: "Test Post") }
53
-
54
- it "should be false by default" do
55
- expect(post.send(:suppress_indexing?)).to eql(false)
56
- end
57
-
58
- it "should be true if overridden locally" do
59
- Lifesaver.suppress_indexing
60
- expect(post.send(:suppress_indexing?)).to eql(true)
61
- end
62
-
63
- it "should be false if override is cancelled" do
64
- Lifesaver.unsuppress_indexing
65
- expect(post.send(:suppress_indexing?)).to eql(false)
66
- end
67
-
68
- it "should be true if set individually" do
69
- post.suppress_indexing
70
- expect(post.send(:suppress_indexing?)).to eql(true)
71
- end
72
-
73
- it "should be false if unset individually" do
74
- post.unsuppress_indexing
75
- expect(post.send(:suppress_indexing?)).to eql(false)
76
- end
77
- end
78
-
79
- describe "#dependent_association_map" do
80
- it "returns an empty Hash when there are no dependent associations" do
81
- expect(Comment.new.send(:dependent_association_map)).to eql({})
82
- end
83
-
84
- it "returns a Hash with the keys of dependent_association" do
85
- dependent_map = Author.new.send(:dependent_association_map)
86
- expect(dependent_map).to eql({authorships: true})
87
- end
88
-
89
- end
90
-
91
- end
@@ -1,111 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Lifesaver do
4
- before(:all) do
5
- Lifesaver.suppress_indexing
6
- Post.destroy_all
7
- Author.destroy_all
8
- Authorship.destroy_all
9
- Affiliate.destroy_all
10
- Comment.destroy_all
11
- Lifesaver.unsuppress_indexing
12
- end
13
- before(:each) do
14
- [Author, Post].each do |klass|
15
- klass.tire.index.delete
16
- klass.tire.create_elasticsearch_index
17
- end
18
-
19
- Lifesaver.suppress_indexing
20
-
21
- @posts = []
22
- @posts << Post.create(
23
- title: "Lifesavers are my favorite candy",
24
- content: "Lorem ipsum",
25
- tags: %w(candy stuff opinions)
26
- )
27
- @posts << Post.create(
28
- title: "Birds are the best animal",
29
- content: "Lorem ipsum",
30
- tags: %w(animals stuff facts)
31
- )
32
- @posts << Post.create(
33
- title: "Chicago Cubs have a winning season",
34
- content: "Lorem ipsum",
35
- tags: %w(sports stuff jokes)
36
- )
37
- @comments = []
38
- @comments << Comment.create(
39
- post: @posts.last,
40
- text: "We love this!"
41
- )
42
- @comments << Comment.create(
43
- post: @posts.last,
44
- text: "We lied. Didn't realize it was a joke."
45
- )
46
- @authors = []
47
- @authors << Author.create(name: "Paul Sorensen")
48
- @authors << Author.create(name: "Paul Sorensen's Ghost Writer")
49
- @authors << Author.create(name: "Theo Epstein")
50
- @affiliates = []
51
- @affiliates << Affiliate.create(name: "Prosper Forebearer")
52
- @affiliates << Affiliate.create(name: "Chicago Cubs")
53
- @authors[0].affiliate_id = @affiliates.first.id
54
- @authors[1].affiliate_id = @affiliates.first.id
55
- @authors[2].affiliate_id = @affiliates.last.id
56
- @authors.each { |a| a.save! }
57
- Authorship.create(post: @posts[0], author: @authors[0])
58
- Authorship.create(post: @posts[1], author: @authors[0])
59
- Authorship.create(post: @posts[1], author: @authors[1])
60
- Authorship.create(post: @posts[2], author: @authors[2])
61
-
62
- Lifesaver.unsuppress_indexing
63
-
64
- [Author, Post].each do |klass|
65
- klass.all.each { |k| k.tire.update_index }
66
- klass.tire.index.refresh
67
- end
68
- end
69
-
70
- after(:each) do
71
- Post.destroy_all
72
- Author.destroy_all
73
- Authorship.destroy_all
74
- Affiliate.destroy_all
75
- Comment.destroy_all
76
- end
77
-
78
- it "should traverse the provided graph" do
79
- models = Lifesaver::IndexGraph.generate([{"class"=>"author", "id"=>1, "status"=>"changed"}])
80
- expect(models.size).to eql(2)
81
- end
82
-
83
- it "should reindex on destroy" do
84
- @authors[2].destroy
85
- sleep(1.seconds)
86
- expect(Author.search(query: "Theo Epstein").to_a.size).to eql(0)
87
- end
88
-
89
- it "should reindex on update" do
90
- @authors[2].name = "Harry Carry"
91
- @authors[2].save!
92
- sleep(1.seconds) # need to wait for elasticsearch to update
93
- expect(Author.search(query: "Harry Carry").to_a.size).to eql(1)
94
- end
95
-
96
- it "should update distant related indexes" do
97
- @posts[0].tags << 'werd'
98
- @posts[0].save!
99
- sleep(1.seconds)
100
- expect(Author.search(query: "werd").to_a.size).to eql(1)
101
- end
102
-
103
- it "should update related indexes if saved model doesn't have index" do
104
- @comments[0].text = "We hate this!"
105
- @comments[0].save!
106
- sleep(1.seconds)
107
- result = Post.search(query: "Chicago").to_a.first
108
- comment_text = result.comments.first.text
109
- expect(comment_text).to eql("We hate this!")
110
- end
111
- end