bullet 5.5.0 → 6.1.5
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.
- checksums.yaml +5 -5
- data/.github/workflows/main.yml +66 -0
- data/CHANGELOG.md +83 -1
- data/Gemfile +6 -1
- data/Gemfile.mongoid-7.0 +15 -0
- data/Gemfile.rails-4.0 +1 -1
- data/Gemfile.rails-4.1 +1 -1
- data/Gemfile.rails-4.2 +1 -1
- data/Gemfile.rails-5.0 +2 -2
- data/Gemfile.rails-5.1 +15 -0
- data/Gemfile.rails-5.2 +15 -0
- data/Gemfile.rails-6.0 +15 -0
- data/Gemfile.rails-6.1 +15 -0
- data/Guardfile +2 -2
- data/Hacking.md +1 -1
- data/README.md +58 -37
- data/Rakefile +20 -21
- data/bullet.gemspec +21 -15
- data/lib/bullet/active_job.rb +13 -0
- data/lib/bullet/active_record4.rb +15 -34
- data/lib/bullet/active_record41.rb +14 -31
- data/lib/bullet/active_record42.rb +23 -36
- data/lib/bullet/active_record5.rb +178 -158
- data/lib/bullet/active_record52.rb +251 -0
- data/lib/bullet/active_record60.rb +278 -0
- data/lib/bullet/active_record61.rb +278 -0
- data/lib/bullet/bullet_xhr.js +64 -0
- data/lib/bullet/dependency.rb +60 -32
- data/lib/bullet/detector/association.rb +41 -32
- data/lib/bullet/detector/base.rb +2 -0
- data/lib/bullet/detector/counter_cache.rb +25 -17
- data/lib/bullet/detector/n_plus_one_query.rb +38 -24
- data/lib/bullet/detector/unused_eager_loading.rb +35 -26
- data/lib/bullet/detector.rb +2 -0
- data/lib/bullet/ext/object.rb +9 -5
- data/lib/bullet/ext/string.rb +3 -1
- data/lib/bullet/mongoid4x.rb +9 -8
- data/lib/bullet/mongoid5x.rb +9 -8
- data/lib/bullet/mongoid6x.rb +13 -12
- data/lib/bullet/mongoid7x.rb +57 -0
- data/lib/bullet/notification/base.rb +28 -25
- data/lib/bullet/notification/counter_cache.rb +3 -1
- data/lib/bullet/notification/n_plus_one_query.rb +8 -7
- data/lib/bullet/notification/unused_eager_loading.rb +8 -7
- data/lib/bullet/notification.rb +4 -1
- data/lib/bullet/notification_collector.rb +2 -1
- data/lib/bullet/rack.rb +66 -35
- data/lib/bullet/registry/association.rb +2 -0
- data/lib/bullet/registry/base.rb +2 -0
- data/lib/bullet/registry/object.rb +2 -0
- data/lib/bullet/registry.rb +2 -0
- data/lib/bullet/stack_trace_filter.rb +50 -20
- data/lib/bullet/version.rb +3 -2
- data/lib/bullet.rb +136 -55
- data/lib/generators/bullet/install_generator.rb +48 -0
- data/perf/benchmark.rb +19 -22
- data/rails/init.rb +2 -0
- data/spec/bullet/detector/association_spec.rb +6 -4
- data/spec/bullet/detector/base_spec.rb +2 -0
- data/spec/bullet/detector/counter_cache_spec.rb +17 -15
- data/spec/bullet/detector/n_plus_one_query_spec.rb +75 -46
- data/spec/bullet/detector/unused_eager_loading_spec.rb +45 -26
- data/spec/bullet/ext/object_spec.rb +18 -11
- data/spec/bullet/ext/string_spec.rb +7 -5
- data/spec/bullet/notification/base_spec.rb +38 -39
- data/spec/bullet/notification/counter_cache_spec.rb +5 -3
- data/spec/bullet/notification/n_plus_one_query_spec.rb +20 -5
- data/spec/bullet/notification/unused_eager_loading_spec.rb +9 -3
- data/spec/bullet/notification_collector_spec.rb +12 -10
- data/spec/bullet/rack_spec.rb +200 -48
- data/spec/bullet/registry/association_spec.rb +12 -10
- data/spec/bullet/registry/base_spec.rb +22 -20
- data/spec/bullet/registry/object_spec.rb +6 -4
- data/spec/bullet_spec.rb +64 -33
- data/spec/integration/{active_record4 → active_record}/association_spec.rb +238 -223
- data/spec/integration/counter_cache_spec.rb +26 -44
- data/spec/integration/mongoid/association_spec.rb +53 -65
- data/spec/models/address.rb +2 -0
- data/spec/models/attachment.rb +5 -0
- data/spec/models/author.rb +2 -0
- data/spec/models/base_user.rb +2 -0
- data/spec/models/category.rb +2 -0
- data/spec/models/city.rb +2 -0
- data/spec/models/client.rb +4 -0
- data/spec/models/comment.rb +3 -1
- data/spec/models/company.rb +2 -0
- data/spec/models/country.rb +2 -0
- data/spec/models/deal.rb +5 -0
- data/spec/models/document.rb +4 -2
- data/spec/models/entry.rb +2 -0
- data/spec/models/firm.rb +3 -0
- data/spec/models/folder.rb +2 -0
- data/spec/models/group.rb +4 -0
- data/spec/models/mongoid/address.rb +3 -1
- data/spec/models/mongoid/category.rb +4 -2
- data/spec/models/mongoid/comment.rb +3 -1
- data/spec/models/mongoid/company.rb +3 -1
- data/spec/models/mongoid/entry.rb +3 -1
- data/spec/models/mongoid/post.rb +6 -4
- data/spec/models/mongoid/user.rb +2 -0
- data/spec/models/newspaper.rb +3 -1
- data/spec/models/page.rb +2 -0
- data/spec/models/person.rb +2 -0
- data/spec/models/pet.rb +2 -0
- data/spec/models/post.rb +19 -0
- data/spec/models/relationship.rb +2 -0
- data/spec/models/reply.rb +2 -0
- data/spec/models/student.rb +2 -0
- data/spec/models/submission.rb +3 -0
- data/spec/models/teacher.rb +2 -0
- data/spec/models/user.rb +3 -0
- data/spec/models/writer.rb +2 -0
- data/spec/spec_helper.rb +19 -23
- data/spec/support/bullet_ext.rb +10 -9
- data/spec/support/mongo_seed.rb +38 -57
- data/spec/support/rack_double.rb +13 -19
- data/spec/support/sqlite_seed.rb +104 -76
- data/tasks/bullet_tasks.rake +4 -2
- data/test.sh +5 -0
- data/update.sh +3 -0
- metadata +34 -17
- data/.travis.yml +0 -16
- data/spec/integration/active_record5/association_spec.rb +0 -768
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'spec_helper'
|
|
2
4
|
|
|
3
5
|
module Bullet
|
|
@@ -8,62 +10,62 @@ module Bullet
|
|
|
8
10
|
@post2 = Post.last
|
|
9
11
|
end
|
|
10
12
|
|
|
11
|
-
context
|
|
12
|
-
it
|
|
13
|
+
context '.call_association' do
|
|
14
|
+
it 'should add call_object_associations' do
|
|
13
15
|
expect(NPlusOneQuery).to receive(:add_call_object_associations).with(@post, :associations)
|
|
14
16
|
NPlusOneQuery.call_association(@post, :associations)
|
|
15
17
|
end
|
|
16
18
|
end
|
|
17
19
|
|
|
18
|
-
context
|
|
19
|
-
it
|
|
20
|
+
context '.possible?' do
|
|
21
|
+
it 'should be true if possible_objects contain' do
|
|
20
22
|
NPlusOneQuery.add_possible_objects(@post)
|
|
21
23
|
expect(NPlusOneQuery.possible?(@post)).to eq true
|
|
22
24
|
end
|
|
23
25
|
end
|
|
24
26
|
|
|
25
|
-
context
|
|
26
|
-
it
|
|
27
|
+
context '.impossible?' do
|
|
28
|
+
it 'should be true if impossible_objects contain' do
|
|
27
29
|
NPlusOneQuery.add_impossible_object(@post)
|
|
28
30
|
expect(NPlusOneQuery.impossible?(@post)).to eq true
|
|
29
31
|
end
|
|
30
32
|
end
|
|
31
33
|
|
|
32
|
-
context
|
|
33
|
-
it
|
|
34
|
+
context '.association?' do
|
|
35
|
+
it 'should be true if object, associations pair is already existed' do
|
|
34
36
|
NPlusOneQuery.add_object_associations(@post, :association)
|
|
35
37
|
expect(NPlusOneQuery.association?(@post, :association)).to eq true
|
|
36
38
|
end
|
|
37
39
|
|
|
38
|
-
it
|
|
40
|
+
it 'should be false if object, association pair is not existed' do
|
|
39
41
|
NPlusOneQuery.add_object_associations(@post, :association1)
|
|
40
42
|
expect(NPlusOneQuery.association?(@post, :associatio2)).to eq false
|
|
41
43
|
end
|
|
42
44
|
end
|
|
43
45
|
|
|
44
|
-
context
|
|
45
|
-
it
|
|
46
|
+
context '.conditions_met?' do
|
|
47
|
+
it 'should be true if object is possible, not impossible and object, associations pair is not already existed' do
|
|
46
48
|
allow(NPlusOneQuery).to receive(:possible?).with(@post).and_return(true)
|
|
47
49
|
allow(NPlusOneQuery).to receive(:impossible?).with(@post).and_return(false)
|
|
48
50
|
allow(NPlusOneQuery).to receive(:association?).with(@post, :associations).and_return(false)
|
|
49
51
|
expect(NPlusOneQuery.conditions_met?(@post, :associations)).to eq true
|
|
50
52
|
end
|
|
51
53
|
|
|
52
|
-
it
|
|
54
|
+
it 'should be false if object is not possible, not impossible and object, associations pair is not already existed' do
|
|
53
55
|
allow(NPlusOneQuery).to receive(:possible?).with(@post).and_return(false)
|
|
54
56
|
allow(NPlusOneQuery).to receive(:impossible?).with(@post).and_return(false)
|
|
55
57
|
allow(NPlusOneQuery).to receive(:association?).with(@post, :associations).and_return(false)
|
|
56
58
|
expect(NPlusOneQuery.conditions_met?(@post, :associations)).to eq false
|
|
57
59
|
end
|
|
58
60
|
|
|
59
|
-
it
|
|
61
|
+
it 'should be false if object is possible, but impossible and object, associations pair is not already existed' do
|
|
60
62
|
allow(NPlusOneQuery).to receive(:possible?).with(@post).and_return(true)
|
|
61
63
|
allow(NPlusOneQuery).to receive(:impossible?).with(@post).and_return(true)
|
|
62
64
|
allow(NPlusOneQuery).to receive(:association?).with(@post, :associations).and_return(false)
|
|
63
65
|
expect(NPlusOneQuery.conditions_met?(@post, :associations)).to eq false
|
|
64
66
|
end
|
|
65
67
|
|
|
66
|
-
it
|
|
68
|
+
it 'should be false if object is possible, not impossible and object, associations pair is already existed' do
|
|
67
69
|
allow(NPlusOneQuery).to receive(:possible?).with(@post).and_return(true)
|
|
68
70
|
allow(NPlusOneQuery).to receive(:impossible?).with(@post).and_return(false)
|
|
69
71
|
allow(NPlusOneQuery).to receive(:association?).with(@post, :associations).and_return(true)
|
|
@@ -71,79 +73,106 @@ module Bullet
|
|
|
71
73
|
end
|
|
72
74
|
end
|
|
73
75
|
|
|
74
|
-
context
|
|
75
|
-
it
|
|
76
|
+
context '.call_association' do
|
|
77
|
+
it 'should create notification if conditions met' do
|
|
76
78
|
expect(NPlusOneQuery).to receive(:conditions_met?).with(@post, :association).and_return(true)
|
|
77
|
-
expect(NPlusOneQuery).to receive(:caller_in_project).and_return([
|
|
78
|
-
expect(NPlusOneQuery).to receive(:create_notification).with([
|
|
79
|
+
expect(NPlusOneQuery).to receive(:caller_in_project).and_return(%w[caller])
|
|
80
|
+
expect(NPlusOneQuery).to receive(:create_notification).with(%w[caller], 'Post', :association)
|
|
79
81
|
NPlusOneQuery.call_association(@post, :association)
|
|
80
82
|
end
|
|
81
83
|
|
|
82
|
-
it
|
|
84
|
+
it 'should not create notification if conditions not met' do
|
|
83
85
|
expect(NPlusOneQuery).to receive(:conditions_met?).with(@post, :association).and_return(false)
|
|
84
86
|
expect(NPlusOneQuery).not_to receive(:caller_in_project!)
|
|
85
|
-
expect(NPlusOneQuery).not_to receive(:create_notification).with(
|
|
87
|
+
expect(NPlusOneQuery).not_to receive(:create_notification).with('Post', :association)
|
|
86
88
|
NPlusOneQuery.call_association(@post, :association)
|
|
87
89
|
end
|
|
88
90
|
|
|
89
|
-
context
|
|
90
|
-
before { Bullet.stacktrace_excludes = [
|
|
91
|
+
context 'stacktrace_excludes' do
|
|
92
|
+
before { Bullet.stacktrace_excludes = [/def/] }
|
|
91
93
|
after { Bullet.stacktrace_excludes = nil }
|
|
92
94
|
|
|
93
|
-
it
|
|
94
|
-
in_project = File.join(Dir.pwd, 'abc', 'abc.rb')
|
|
95
|
-
included_path = '/ghi/ghi.rb'
|
|
96
|
-
excluded_path = '/def/def.rb'
|
|
95
|
+
it 'should not create notification when stacktrace contains paths that are in the exclude list' do
|
|
96
|
+
in_project = OpenStruct.new(absolute_path: File.join(Dir.pwd, 'abc', 'abc.rb'))
|
|
97
|
+
included_path = OpenStruct.new(absolute_path: '/ghi/ghi.rb')
|
|
98
|
+
excluded_path = OpenStruct.new(absolute_path: '/def/def.rb')
|
|
99
|
+
|
|
100
|
+
expect(NPlusOneQuery).to receive(:caller_locations).and_return([in_project, included_path, excluded_path])
|
|
101
|
+
expect(NPlusOneQuery).to_not receive(:create_notification)
|
|
102
|
+
NPlusOneQuery.call_association(@post, :association)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# just a sanity spec to make sure the following spec works correctly
|
|
106
|
+
it "should create notification when stacktrace contains methods that aren't in the exclude list" do
|
|
107
|
+
method = NPlusOneQuery.method(:excluded_stacktrace_path?).source_location
|
|
108
|
+
in_project = OpenStruct.new(absolute_path: File.join(Dir.pwd, 'abc', 'abc.rb'))
|
|
109
|
+
excluded_path = OpenStruct.new(absolute_path: method.first, lineno: method.last)
|
|
110
|
+
|
|
111
|
+
expect(NPlusOneQuery).to receive(:caller_locations).at_least(1).and_return([in_project, excluded_path])
|
|
112
|
+
expect(NPlusOneQuery).to receive(:conditions_met?).and_return(true)
|
|
113
|
+
expect(NPlusOneQuery).to receive(:create_notification)
|
|
114
|
+
NPlusOneQuery.call_association(@post, :association)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it 'should not create notification when stacktrace contains methods that are in the exclude list' do
|
|
118
|
+
method = NPlusOneQuery.method(:excluded_stacktrace_path?).source_location
|
|
119
|
+
Bullet.stacktrace_excludes = [method]
|
|
120
|
+
in_project = OpenStruct.new(absolute_path: File.join(Dir.pwd, 'abc', 'abc.rb'))
|
|
121
|
+
excluded_path = OpenStruct.new(absolute_path: method.first, lineno: method.last)
|
|
97
122
|
|
|
98
|
-
expect(NPlusOneQuery).to receive(:
|
|
123
|
+
expect(NPlusOneQuery).to receive(:caller_locations).and_return([in_project, excluded_path])
|
|
99
124
|
expect(NPlusOneQuery).to_not receive(:create_notification)
|
|
100
125
|
NPlusOneQuery.call_association(@post, :association)
|
|
101
126
|
end
|
|
102
127
|
end
|
|
103
128
|
end
|
|
104
129
|
|
|
105
|
-
context
|
|
106
|
-
it
|
|
107
|
-
in_project = File.join(Dir.pwd, 'abc', 'abc.rb')
|
|
108
|
-
not_in_project = '/def/def.rb'
|
|
130
|
+
context '.caller_in_project' do
|
|
131
|
+
it 'should include only paths that are in the project' do
|
|
132
|
+
in_project = OpenStruct.new(absolute_path: File.join(Dir.pwd, 'abc', 'abc.rb'))
|
|
133
|
+
not_in_project = OpenStruct.new(absolute_path: '/def/def.rb')
|
|
109
134
|
|
|
110
|
-
expect(NPlusOneQuery).to receive(:
|
|
135
|
+
expect(NPlusOneQuery).to receive(:caller_locations).and_return([in_project, not_in_project])
|
|
111
136
|
expect(NPlusOneQuery).to receive(:conditions_met?).with(@post, :association).and_return(true)
|
|
112
|
-
expect(NPlusOneQuery).to receive(:create_notification).with([in_project],
|
|
137
|
+
expect(NPlusOneQuery).to receive(:create_notification).with([in_project], 'Post', :association)
|
|
113
138
|
NPlusOneQuery.call_association(@post, :association)
|
|
114
139
|
end
|
|
115
140
|
|
|
116
|
-
context
|
|
117
|
-
before { Bullet.stacktrace_includes = [
|
|
141
|
+
context 'stacktrace_includes' do
|
|
142
|
+
before { Bullet.stacktrace_includes = ['def', /xyz/] }
|
|
118
143
|
after { Bullet.stacktrace_includes = nil }
|
|
119
144
|
|
|
120
|
-
it
|
|
121
|
-
in_project = File.join(Dir.pwd, 'abc', 'abc.rb')
|
|
122
|
-
included_gems = ['/def/def.rb', 'xyz/xyz.rb']
|
|
123
|
-
excluded_gem = '/ghi/ghi.rb'
|
|
145
|
+
it 'should include paths that are in the stacktrace_include list' do
|
|
146
|
+
in_project = OpenStruct.new(absolute_path: File.join(Dir.pwd, 'abc', 'abc.rb'))
|
|
147
|
+
included_gems = [OpenStruct.new(absolute_path: '/def/def.rb'), OpenStruct.new(absolute_path: 'xyz/xyz.rb')]
|
|
148
|
+
excluded_gem = OpenStruct.new(absolute_path: '/ghi/ghi.rb')
|
|
124
149
|
|
|
125
|
-
expect(NPlusOneQuery).to receive(:
|
|
150
|
+
expect(NPlusOneQuery).to receive(:caller_locations).and_return([in_project, *included_gems, excluded_gem])
|
|
126
151
|
expect(NPlusOneQuery).to receive(:conditions_met?).with(@post, :association).and_return(true)
|
|
127
|
-
expect(NPlusOneQuery).to receive(:create_notification).with(
|
|
152
|
+
expect(NPlusOneQuery).to receive(:create_notification).with(
|
|
153
|
+
[in_project, *included_gems],
|
|
154
|
+
'Post',
|
|
155
|
+
:association
|
|
156
|
+
)
|
|
128
157
|
NPlusOneQuery.call_association(@post, :association)
|
|
129
158
|
end
|
|
130
159
|
end
|
|
131
160
|
end
|
|
132
161
|
|
|
133
|
-
context
|
|
134
|
-
it
|
|
162
|
+
context '.add_possible_objects' do
|
|
163
|
+
it 'should add possible objects' do
|
|
135
164
|
NPlusOneQuery.add_possible_objects([@post, @post2])
|
|
136
165
|
expect(NPlusOneQuery.possible_objects).to be_include(@post.bullet_key)
|
|
137
166
|
expect(NPlusOneQuery.possible_objects).to be_include(@post2.bullet_key)
|
|
138
167
|
end
|
|
139
168
|
|
|
140
|
-
it
|
|
169
|
+
it 'should not raise error if object is nil' do
|
|
141
170
|
expect { NPlusOneQuery.add_possible_objects(nil) }.not_to raise_error
|
|
142
171
|
end
|
|
143
172
|
end
|
|
144
173
|
|
|
145
|
-
context
|
|
146
|
-
it
|
|
174
|
+
context '.add_impossible_object' do
|
|
175
|
+
it 'should add impossible object' do
|
|
147
176
|
NPlusOneQuery.add_impossible_object(@post)
|
|
148
177
|
expect(NPlusOneQuery.impossible_objects).to be_include(@post.bullet_key)
|
|
149
178
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'spec_helper'
|
|
2
4
|
|
|
3
5
|
module Bullet
|
|
@@ -9,68 +11,85 @@ module Bullet
|
|
|
9
11
|
@post3 = Post.last
|
|
10
12
|
end
|
|
11
13
|
|
|
12
|
-
context
|
|
13
|
-
it
|
|
14
|
+
context '.call_associations' do
|
|
15
|
+
it 'should get empty array if eager_loadings' do
|
|
14
16
|
expect(UnusedEagerLoading.send(:call_associations, @post.bullet_key, Set.new([:association]))).to be_empty
|
|
15
17
|
end
|
|
16
18
|
|
|
17
|
-
it
|
|
19
|
+
it 'should get call associations if object and association are both in eager_loadings and call_object_associations' do
|
|
18
20
|
UnusedEagerLoading.add_eager_loadings([@post], :association)
|
|
19
21
|
UnusedEagerLoading.add_call_object_associations(@post, :association)
|
|
20
|
-
expect(UnusedEagerLoading.send(:call_associations, @post.bullet_key, Set.new([:association]))).to eq(
|
|
22
|
+
expect(UnusedEagerLoading.send(:call_associations, @post.bullet_key, Set.new([:association]))).to eq(
|
|
23
|
+
[:association]
|
|
24
|
+
)
|
|
21
25
|
end
|
|
22
26
|
|
|
23
|
-
it
|
|
27
|
+
it 'should not get call associations if not exist in call_object_associations' do
|
|
24
28
|
UnusedEagerLoading.add_eager_loadings([@post], :association)
|
|
25
29
|
expect(UnusedEagerLoading.send(:call_associations, @post.bullet_key, Set.new([:association]))).to be_empty
|
|
26
30
|
end
|
|
27
31
|
end
|
|
28
32
|
|
|
29
|
-
context
|
|
30
|
-
it
|
|
31
|
-
expect(UnusedEagerLoading.send(:diff_object_associations, @post.bullet_key, Set.new([:association]))).to eq(
|
|
33
|
+
context '.diff_object_associations' do
|
|
34
|
+
it 'should return associations not exist in call_association' do
|
|
35
|
+
expect(UnusedEagerLoading.send(:diff_object_associations, @post.bullet_key, Set.new([:association]))).to eq(
|
|
36
|
+
[:association]
|
|
37
|
+
)
|
|
32
38
|
end
|
|
33
39
|
|
|
34
|
-
it
|
|
40
|
+
it 'should return empty if associations exist in call_association' do
|
|
35
41
|
UnusedEagerLoading.add_eager_loadings([@post], :association)
|
|
36
42
|
UnusedEagerLoading.add_call_object_associations(@post, :association)
|
|
37
|
-
expect(
|
|
43
|
+
expect(
|
|
44
|
+
UnusedEagerLoading.send(:diff_object_associations, @post.bullet_key, Set.new([:association]))
|
|
45
|
+
).to be_empty
|
|
38
46
|
end
|
|
39
47
|
end
|
|
40
48
|
|
|
41
|
-
context
|
|
42
|
-
let(:paths) { [
|
|
43
|
-
it
|
|
49
|
+
context '.check_unused_preload_associations' do
|
|
50
|
+
let(:paths) { %w[/dir1 /dir1/subdir] }
|
|
51
|
+
it 'should create notification if object_association_diff is not empty' do
|
|
44
52
|
UnusedEagerLoading.add_object_associations(@post, :association)
|
|
45
53
|
allow(UnusedEagerLoading).to receive(:caller_in_project).and_return(paths)
|
|
46
|
-
expect(UnusedEagerLoading).to receive(:create_notification).with(paths,
|
|
54
|
+
expect(UnusedEagerLoading).to receive(:create_notification).with(paths, 'Post', [:association])
|
|
47
55
|
UnusedEagerLoading.check_unused_preload_associations
|
|
48
56
|
end
|
|
49
57
|
|
|
50
|
-
it
|
|
58
|
+
it 'should not create notification if object_association_diff is empty' do
|
|
51
59
|
UnusedEagerLoading.add_object_associations(@post, :association)
|
|
52
60
|
UnusedEagerLoading.add_eager_loadings([@post], :association)
|
|
53
61
|
UnusedEagerLoading.add_call_object_associations(@post, :association)
|
|
54
|
-
expect(
|
|
55
|
-
|
|
62
|
+
expect(
|
|
63
|
+
UnusedEagerLoading.send(:diff_object_associations, @post.bullet_key, Set.new([:association]))
|
|
64
|
+
).to be_empty
|
|
65
|
+
expect(UnusedEagerLoading).not_to receive(:create_notification).with('Post', [:association])
|
|
56
66
|
UnusedEagerLoading.check_unused_preload_associations
|
|
57
67
|
end
|
|
58
68
|
end
|
|
59
69
|
|
|
60
|
-
context
|
|
61
|
-
it
|
|
70
|
+
context '.add_eager_loadings' do
|
|
71
|
+
it 'should add objects, associations pair when eager_loadings are empty' do
|
|
62
72
|
UnusedEagerLoading.add_eager_loadings([@post, @post2], :associations)
|
|
63
|
-
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include(
|
|
73
|
+
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include(
|
|
74
|
+
[@post.bullet_key, @post2.bullet_key],
|
|
75
|
+
:associations
|
|
76
|
+
)
|
|
64
77
|
end
|
|
65
78
|
|
|
66
|
-
it
|
|
79
|
+
it 'should add objects, associations pair for existing eager_loadings' do
|
|
67
80
|
UnusedEagerLoading.add_eager_loadings([@post, @post2], :association1)
|
|
68
81
|
UnusedEagerLoading.add_eager_loadings([@post, @post2], :association2)
|
|
69
|
-
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include(
|
|
70
|
-
|
|
82
|
+
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include(
|
|
83
|
+
[@post.bullet_key, @post2.bullet_key],
|
|
84
|
+
:association1
|
|
85
|
+
)
|
|
86
|
+
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include(
|
|
87
|
+
[@post.bullet_key, @post2.bullet_key],
|
|
88
|
+
:association2
|
|
89
|
+
)
|
|
71
90
|
end
|
|
72
91
|
|
|
73
|
-
it
|
|
92
|
+
it 'should merge objects, associations pair for existing eager_loadings' do
|
|
74
93
|
UnusedEagerLoading.add_eager_loadings([@post], :association1)
|
|
75
94
|
UnusedEagerLoading.add_eager_loadings([@post, @post2], :association2)
|
|
76
95
|
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key], :association1)
|
|
@@ -78,7 +97,7 @@ module Bullet
|
|
|
78
97
|
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post2.bullet_key], :association2)
|
|
79
98
|
end
|
|
80
99
|
|
|
81
|
-
it
|
|
100
|
+
it 'should vmerge objects recursively, associations pair for existing eager_loadings' do
|
|
82
101
|
UnusedEagerLoading.add_eager_loadings([@post, @post2], :association1)
|
|
83
102
|
UnusedEagerLoading.add_eager_loadings([@post, @post3], :association1)
|
|
84
103
|
UnusedEagerLoading.add_eager_loadings([@post, @post3], :association2)
|
|
@@ -89,7 +108,7 @@ module Bullet
|
|
|
89
108
|
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post3.bullet_key], :association2)
|
|
90
109
|
end
|
|
91
110
|
|
|
92
|
-
it
|
|
111
|
+
it 'should delete objects, associations pair for existing eager_loadings' do
|
|
93
112
|
UnusedEagerLoading.add_eager_loadings([@post, @post2], :association1)
|
|
94
113
|
UnusedEagerLoading.add_eager_loadings([@post], :association2)
|
|
95
114
|
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key], :association1)
|
|
@@ -1,37 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'spec_helper'
|
|
2
4
|
|
|
3
5
|
describe Object do
|
|
4
|
-
context
|
|
5
|
-
it
|
|
6
|
+
context 'bullet_key' do
|
|
7
|
+
it 'should return class and id composition' do
|
|
6
8
|
post = Post.first
|
|
7
9
|
expect(post.bullet_key).to eq("Post:#{post.id}")
|
|
8
10
|
end
|
|
9
11
|
|
|
10
12
|
if mongoid?
|
|
11
|
-
it
|
|
13
|
+
it 'should return class with namespace and id composition' do
|
|
12
14
|
post = Mongoid::Post.first
|
|
13
15
|
expect(post.bullet_key).to eq("Mongoid::Post:#{post.id}")
|
|
14
16
|
end
|
|
15
17
|
end
|
|
16
18
|
end
|
|
17
19
|
|
|
18
|
-
context
|
|
19
|
-
it
|
|
20
|
+
context 'bullet_primary_key_value' do
|
|
21
|
+
it 'should return id' do
|
|
20
22
|
post = Post.first
|
|
21
|
-
expect(post.
|
|
23
|
+
expect(post.bullet_primary_key_value).to eq(post.id)
|
|
22
24
|
end
|
|
23
25
|
|
|
24
|
-
it
|
|
26
|
+
it 'should return primary key value' do
|
|
25
27
|
post = Post.first
|
|
26
28
|
Post.primary_key = 'name'
|
|
27
|
-
expect(post.
|
|
29
|
+
expect(post.bullet_primary_key_value).to eq(post.name)
|
|
28
30
|
Post.primary_key = 'id'
|
|
29
31
|
end
|
|
30
32
|
|
|
31
|
-
it
|
|
33
|
+
it 'should return value for multiple primary keys' do
|
|
32
34
|
post = Post.first
|
|
33
|
-
allow(Post).to receive(:primary_keys).and_return([
|
|
34
|
-
expect(post.
|
|
35
|
+
allow(Post).to receive(:primary_keys).and_return(%i[category_id writer_id])
|
|
36
|
+
expect(post.bullet_primary_key_value).to eq("#{post.category_id},#{post.writer_id}")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'it should return nil for unpersisted records' do
|
|
40
|
+
post = Post.new(id: 123)
|
|
41
|
+
expect(post.bullet_primary_key_value).to be_nil
|
|
35
42
|
end
|
|
36
43
|
end
|
|
37
44
|
end
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'spec_helper'
|
|
2
4
|
|
|
3
5
|
describe String do
|
|
4
|
-
context
|
|
5
|
-
it
|
|
6
|
-
expect(
|
|
6
|
+
context 'bullet_class_name' do
|
|
7
|
+
it 'should only return class name' do
|
|
8
|
+
expect('Post:1'.bullet_class_name).to eq('Post')
|
|
7
9
|
end
|
|
8
10
|
|
|
9
|
-
it
|
|
10
|
-
expect(
|
|
11
|
+
it 'should return class name with namespace' do
|
|
12
|
+
expect('Mongoid::Post:1234567890'.bullet_class_name).to eq('Mongoid::Post')
|
|
11
13
|
end
|
|
12
14
|
end
|
|
13
15
|
end
|
|
@@ -1,45 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'spec_helper'
|
|
2
4
|
|
|
3
5
|
module Bullet
|
|
4
6
|
module Notification
|
|
5
7
|
describe Base do
|
|
6
|
-
subject { Base.new(Post, [
|
|
8
|
+
subject { Base.new(Post, %i[comments votes]) }
|
|
7
9
|
|
|
8
|
-
context
|
|
9
|
-
it
|
|
10
|
+
context '#title' do
|
|
11
|
+
it 'should raise NoMethodError' do
|
|
10
12
|
expect { subject.title }.to raise_error(NoMethodError)
|
|
11
13
|
end
|
|
12
14
|
end
|
|
13
15
|
|
|
14
|
-
context
|
|
15
|
-
it
|
|
16
|
+
context '#body' do
|
|
17
|
+
it 'should raise NoMethodError' do
|
|
16
18
|
expect { subject.body }.to raise_error(NoMethodError)
|
|
17
19
|
end
|
|
18
20
|
end
|
|
19
21
|
|
|
20
|
-
context
|
|
21
|
-
it
|
|
22
|
+
context '#whoami' do
|
|
23
|
+
it 'should display user name' do
|
|
22
24
|
user = `whoami`.chomp
|
|
23
25
|
expect(subject.whoami).to eq("user: #{user}")
|
|
24
26
|
end
|
|
25
27
|
|
|
26
|
-
it
|
|
27
|
-
temp_env_variable(
|
|
28
|
-
expect(subject.whoami).to eq("user: bogus")
|
|
29
|
-
end
|
|
28
|
+
it 'should leverage ENV parameter' do
|
|
29
|
+
temp_env_variable('USER', 'bogus') { expect(subject.whoami).to eq('user: bogus') }
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
it
|
|
33
|
-
temp_env_variable(
|
|
34
|
-
expect(subject).to receive(:`).with(
|
|
35
|
-
expect(subject.whoami).to eq(
|
|
32
|
+
it 'should return blank if no user available' do
|
|
33
|
+
temp_env_variable('USER', '') do
|
|
34
|
+
expect(subject).to receive(:`).with('whoami').and_return('')
|
|
35
|
+
expect(subject.whoami).to eq('')
|
|
36
36
|
end
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
-
it
|
|
40
|
-
temp_env_variable(
|
|
41
|
-
expect(subject).to receive(:`).with(
|
|
42
|
-
expect(subject.whoami).to eq(
|
|
39
|
+
it 'should return blank if whoami is not available' do
|
|
40
|
+
temp_env_variable('USER', '') do
|
|
41
|
+
expect(subject).to receive(:`).with('whoami').and_raise(Errno::ENOENT)
|
|
42
|
+
expect(subject.whoami).to eq('')
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
|
|
@@ -50,43 +50,42 @@ module Bullet
|
|
|
50
50
|
ensure
|
|
51
51
|
ENV[name] = old_value
|
|
52
52
|
end
|
|
53
|
-
|
|
54
53
|
end
|
|
55
54
|
|
|
56
|
-
context
|
|
57
|
-
it
|
|
58
|
-
allow(subject).to receive(:body).and_return(
|
|
59
|
-
allow(subject).to receive(:call_stack_messages).and_return(
|
|
55
|
+
context '#body_with_caller' do
|
|
56
|
+
it 'should return body' do
|
|
57
|
+
allow(subject).to receive(:body).and_return('body')
|
|
58
|
+
allow(subject).to receive(:call_stack_messages).and_return('call_stack_messages')
|
|
60
59
|
expect(subject.body_with_caller).to eq("body\ncall_stack_messages\n")
|
|
61
60
|
end
|
|
62
61
|
end
|
|
63
62
|
|
|
64
|
-
context
|
|
65
|
-
it
|
|
66
|
-
allow(subject).to receive(:whoami).and_return(
|
|
67
|
-
allow(subject).to receive(:url).and_return(
|
|
68
|
-
allow(subject).to receive(:title).and_return(
|
|
69
|
-
allow(subject).to receive(:body_with_caller).and_return(
|
|
70
|
-
expect(subject.notification_data).to eq(:
|
|
63
|
+
context '#notification_data' do
|
|
64
|
+
it 'should return notification data' do
|
|
65
|
+
allow(subject).to receive(:whoami).and_return('whoami')
|
|
66
|
+
allow(subject).to receive(:url).and_return('url')
|
|
67
|
+
allow(subject).to receive(:title).and_return('title')
|
|
68
|
+
allow(subject).to receive(:body_with_caller).and_return('body_with_caller')
|
|
69
|
+
expect(subject.notification_data).to eq(user: 'whoami', url: 'url', title: 'title', body: 'body_with_caller')
|
|
71
70
|
end
|
|
72
71
|
end
|
|
73
72
|
|
|
74
|
-
context
|
|
75
|
-
it
|
|
73
|
+
context '#notify_inline' do
|
|
74
|
+
it 'should send full_notice to notifier' do
|
|
76
75
|
notifier = double
|
|
77
76
|
allow(subject).to receive(:notifier).and_return(notifier)
|
|
78
|
-
allow(subject).to receive(:notification_data).and_return(:
|
|
79
|
-
expect(notifier).to receive(:inline_notify).with(:
|
|
77
|
+
allow(subject).to receive(:notification_data).and_return(foo: :bar)
|
|
78
|
+
expect(notifier).to receive(:inline_notify).with(foo: :bar)
|
|
80
79
|
subject.notify_inline
|
|
81
80
|
end
|
|
82
81
|
end
|
|
83
82
|
|
|
84
|
-
context
|
|
85
|
-
it
|
|
83
|
+
context '#notify_out_of_channel' do
|
|
84
|
+
it 'should send full_out_of_channel to notifier' do
|
|
86
85
|
notifier = double
|
|
87
86
|
allow(subject).to receive(:notifier).and_return(notifier)
|
|
88
|
-
allow(subject).to receive(:notification_data).and_return(:
|
|
89
|
-
expect(notifier).to receive(:out_of_channel_notify).with(:
|
|
87
|
+
allow(subject).to receive(:notification_data).and_return(foo: :bar)
|
|
88
|
+
expect(notifier).to receive(:out_of_channel_notify).with(foo: :bar)
|
|
90
89
|
subject.notify_out_of_channel
|
|
91
90
|
end
|
|
92
91
|
end
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'spec_helper'
|
|
2
4
|
|
|
3
5
|
module Bullet
|
|
4
6
|
module Notification
|
|
5
7
|
describe CounterCache do
|
|
6
|
-
subject { CounterCache.new(Post, [
|
|
8
|
+
subject { CounterCache.new(Post, %i[comments votes]) }
|
|
7
9
|
|
|
8
|
-
it { expect(subject.body).to eq(
|
|
9
|
-
it { expect(subject.title).to eq(
|
|
10
|
+
it { expect(subject.body).to eq(' Post => [:comments, :votes]') }
|
|
11
|
+
it { expect(subject.title).to eq('Need Counter Cache') }
|
|
10
12
|
end
|
|
11
13
|
end
|
|
12
14
|
end
|
|
@@ -1,14 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'spec_helper'
|
|
2
4
|
|
|
3
5
|
module Bullet
|
|
4
6
|
module Notification
|
|
5
7
|
describe NPlusOneQuery do
|
|
6
|
-
subject { NPlusOneQuery.new([[
|
|
8
|
+
subject { NPlusOneQuery.new([%w[caller1 caller2]], Post, %i[comments votes], 'path') }
|
|
7
9
|
|
|
8
|
-
it
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
it do
|
|
11
|
+
expect(subject.body_with_caller).to eq(
|
|
12
|
+
" Post => [:comments, :votes]\n Add to your query: .includes([:comments, :votes])\nCall stack\n caller1\n caller2\n"
|
|
13
|
+
)
|
|
14
|
+
end
|
|
15
|
+
it do
|
|
16
|
+
expect([subject.body_with_caller, subject.body_with_caller]).to eq(
|
|
17
|
+
[
|
|
18
|
+
" Post => [:comments, :votes]\n Add to your query: .includes([:comments, :votes])\nCall stack\n caller1\n caller2\n",
|
|
19
|
+
" Post => [:comments, :votes]\n Add to your query: .includes([:comments, :votes])\nCall stack\n caller1\n caller2\n"
|
|
20
|
+
]
|
|
21
|
+
)
|
|
22
|
+
end
|
|
23
|
+
it do
|
|
24
|
+
expect(subject.body).to eq(" Post => [:comments, :votes]\n Add to your query: .includes([:comments, :votes])")
|
|
25
|
+
end
|
|
26
|
+
it { expect(subject.title).to eq('USE eager loading in path') }
|
|
12
27
|
end
|
|
13
28
|
end
|
|
14
29
|
end
|
|
@@ -1,12 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'spec_helper'
|
|
2
4
|
|
|
3
5
|
module Bullet
|
|
4
6
|
module Notification
|
|
5
7
|
describe UnusedEagerLoading do
|
|
6
|
-
subject { UnusedEagerLoading.new([
|
|
8
|
+
subject { UnusedEagerLoading.new([''], Post, %i[comments votes], 'path') }
|
|
7
9
|
|
|
8
|
-
it
|
|
9
|
-
|
|
10
|
+
it do
|
|
11
|
+
expect(subject.body).to eq(
|
|
12
|
+
" Post => [:comments, :votes]\n Remove from your query: .includes([:comments, :votes])"
|
|
13
|
+
)
|
|
14
|
+
end
|
|
15
|
+
it { expect(subject.title).to eq('AVOID eager loading in path') }
|
|
10
16
|
end
|
|
11
17
|
end
|
|
12
18
|
end
|