lifesaver 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +1 -0
- data/.travis.yml +3 -1
- data/CHANGELOG.md +7 -0
- data/Gemfile +4 -0
- data/README.md +33 -13
- data/lib/lifesaver.rb +34 -11
- data/lib/lifesaver/config.rb +16 -0
- data/lib/lifesaver/index_worker.rb +10 -10
- data/lib/lifesaver/indexing/enqueuer.rb +37 -0
- data/lib/lifesaver/indexing/indexer.rb +40 -0
- data/lib/lifesaver/indexing/model_additions.rb +55 -0
- data/lib/lifesaver/notification/eager_loader.rb +48 -0
- data/lib/lifesaver/notification/enqueuer.rb +24 -0
- data/lib/lifesaver/notification/indexing_graph.rb +91 -0
- data/lib/lifesaver/notification/model_additions.rb +104 -0
- data/lib/lifesaver/notification/notifiable_associations.rb +49 -0
- data/lib/lifesaver/notification/traversal_queue.rb +48 -0
- data/lib/lifesaver/railtie.rb +4 -3
- data/lib/lifesaver/serialized_model.rb +3 -0
- data/lib/lifesaver/version.rb +1 -1
- data/lib/lifesaver/visitor_worker.rb +8 -4
- data/spec/integration/lifesaver_spec.rb +78 -0
- data/spec/spec_helper.rb +12 -10
- data/spec/support/active_record.rb +3 -3
- data/spec/support/test_models.rb +8 -6
- data/spec/support/tire_helper.rb +37 -0
- data/spec/unit/config_spec.rb +17 -0
- data/spec/unit/indexing/indexer_spec.rb +51 -0
- data/spec/unit/indexing/model_addtions_spec.rb +53 -0
- data/spec/unit/notification/eager_loader_spec.rb +64 -0
- data/spec/unit/notification/enqueuer_spec.rb +39 -0
- data/spec/unit/notification/indexing_graph_spec.rb +73 -0
- data/spec/unit/notification/model_additions_spec.rb +69 -0
- data/spec/unit/notification/notifiable_associations_spec.rb +75 -0
- data/spec/unit/notification/traversal_queue_spec.rb +67 -0
- metadata +40 -14
- data/lib/lifesaver/index_graph.rb +0 -53
- data/lib/lifesaver/marshal.rb +0 -43
- data/lib/lifesaver/model_additions.rb +0 -133
- data/spec/lifesaver/index_graph_spec.rb +0 -64
- data/spec/lifesaver/marshal_spec.rb +0 -80
- data/spec/lifesaver/model_additions_spec.rb +0 -91
- 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
|
data/spec/lifesaver_spec.rb
DELETED
@@ -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
|