bullet 5.5.0 → 5.8.0
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 +4 -4
- data/.travis.yml +1 -5
- data/CHANGELOG.md +31 -1
- data/Gemfile +6 -1
- data/Gemfile.rails-5.0 +1 -1
- data/Gemfile.rails-5.1 +15 -0
- data/Gemfile.rails-5.2 +15 -0
- data/Guardfile +2 -2
- data/Hacking.md +1 -1
- data/README.md +20 -23
- data/Rakefile +20 -21
- data/bullet.gemspec +20 -15
- data/lib/bullet/active_record4.rb +18 -14
- data/lib/bullet/active_record41.rb +16 -14
- data/lib/bullet/active_record42.rb +24 -22
- data/lib/bullet/active_record5.rb +102 -91
- data/lib/bullet/active_record52.rb +232 -0
- data/lib/bullet/dependency.rb +9 -1
- data/lib/bullet/detector/association.rb +17 -14
- data/lib/bullet/detector/base.rb +2 -0
- data/lib/bullet/detector/counter_cache.rb +14 -10
- data/lib/bullet/detector/n_plus_one_query.rb +21 -17
- data/lib/bullet/detector/unused_eager_loading.rb +30 -24
- data/lib/bullet/detector.rb +2 -0
- data/lib/bullet/ext/object.rb +6 -4
- data/lib/bullet/ext/string.rb +3 -1
- data/lib/bullet/mongoid4x.rb +7 -2
- data/lib/bullet/mongoid5x.rb +7 -2
- data/lib/bullet/mongoid6x.rb +11 -6
- data/lib/bullet/notification/base.rb +26 -19
- data/lib/bullet/notification/counter_cache.rb +3 -1
- data/lib/bullet/notification/n_plus_one_query.rb +7 -4
- data/lib/bullet/notification/unused_eager_loading.rb +7 -4
- data/lib/bullet/notification.rb +2 -0
- data/lib/bullet/notification_collector.rb +2 -1
- data/lib/bullet/rack.rb +22 -18
- 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 +56 -18
- data/lib/bullet/version.rb +3 -2
- data/lib/bullet.rb +43 -33
- data/lib/generators/bullet/install_generator.rb +48 -0
- data/perf/benchmark.rb +12 -12
- 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 +13 -11
- data/spec/bullet/detector/n_plus_one_query_spec.rb +71 -46
- data/spec/bullet/detector/unused_eager_loading_spec.rb +21 -19
- data/spec/bullet/ext/object_spec.rb +10 -8
- data/spec/bullet/ext/string_spec.rb +7 -5
- data/spec/bullet/notification/base_spec.rb +39 -38
- data/spec/bullet/notification/counter_cache_spec.rb +5 -3
- data/spec/bullet/notification/n_plus_one_query_spec.rb +5 -3
- data/spec/bullet/notification/unused_eager_loading_spec.rb +4 -2
- data/spec/bullet/notification_collector_spec.rb +12 -10
- data/spec/bullet/rack_spec.rb +48 -47
- 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 +24 -3
- data/spec/integration/{active_record4 → active_record}/association_spec.rb +176 -114
- data/spec/integration/counter_cache_spec.rb +15 -13
- data/spec/integration/mongoid/association_spec.rb +35 -33
- data/spec/models/address.rb +2 -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/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 +17 -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 +2 -0
- data/spec/models/teacher.rb +2 -0
- data/spec/models/user.rb +2 -0
- data/spec/models/writer.rb +2 -0
- data/spec/spec_helper.rb +15 -13
- data/spec/support/bullet_ext.rb +2 -0
- data/spec/support/mongo_seed.rb +36 -42
- data/spec/support/rack_double.rb +13 -19
- data/spec/support/sqlite_seed.rb +84 -76
- data/tasks/bullet_tasks.rake +4 -2
- data/test.sh +2 -0
- data/update.sh +2 -0
- metadata +17 -11
- 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,102 @@ 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(['caller'])
|
|
80
|
+
expect(NPlusOneQuery).to receive(:create_notification).with(['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([in_project, *included_gems],
|
|
152
|
+
expect(NPlusOneQuery).to receive(:create_notification).with([in_project, *included_gems], 'Post', :association)
|
|
128
153
|
NPlusOneQuery.call_association(@post, :association)
|
|
129
154
|
end
|
|
130
155
|
end
|
|
131
156
|
end
|
|
132
157
|
|
|
133
|
-
context
|
|
134
|
-
it
|
|
158
|
+
context '.add_possible_objects' do
|
|
159
|
+
it 'should add possible objects' do
|
|
135
160
|
NPlusOneQuery.add_possible_objects([@post, @post2])
|
|
136
161
|
expect(NPlusOneQuery.possible_objects).to be_include(@post.bullet_key)
|
|
137
162
|
expect(NPlusOneQuery.possible_objects).to be_include(@post2.bullet_key)
|
|
138
163
|
end
|
|
139
164
|
|
|
140
|
-
it
|
|
165
|
+
it 'should not raise error if object is nil' do
|
|
141
166
|
expect { NPlusOneQuery.add_possible_objects(nil) }.not_to raise_error
|
|
142
167
|
end
|
|
143
168
|
end
|
|
144
169
|
|
|
145
|
-
context
|
|
146
|
-
it
|
|
170
|
+
context '.add_impossible_object' do
|
|
171
|
+
it 'should add impossible object' do
|
|
147
172
|
NPlusOneQuery.add_impossible_object(@post)
|
|
148
173
|
expect(NPlusOneQuery.impossible_objects).to be_include(@post.bullet_key)
|
|
149
174
|
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,68 @@ 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
22
|
expect(UnusedEagerLoading.send(:call_associations, @post.bullet_key, Set.new([:association]))).to eq([:association])
|
|
21
23
|
end
|
|
22
24
|
|
|
23
|
-
it
|
|
25
|
+
it 'should not get call associations if not exist in call_object_associations' do
|
|
24
26
|
UnusedEagerLoading.add_eager_loadings([@post], :association)
|
|
25
27
|
expect(UnusedEagerLoading.send(:call_associations, @post.bullet_key, Set.new([:association]))).to be_empty
|
|
26
28
|
end
|
|
27
29
|
end
|
|
28
30
|
|
|
29
|
-
context
|
|
30
|
-
it
|
|
31
|
+
context '.diff_object_associations' do
|
|
32
|
+
it 'should return associations not exist in call_association' do
|
|
31
33
|
expect(UnusedEagerLoading.send(:diff_object_associations, @post.bullet_key, Set.new([:association]))).to eq([:association])
|
|
32
34
|
end
|
|
33
35
|
|
|
34
|
-
it
|
|
36
|
+
it 'should return empty if associations exist in call_association' do
|
|
35
37
|
UnusedEagerLoading.add_eager_loadings([@post], :association)
|
|
36
38
|
UnusedEagerLoading.add_call_object_associations(@post, :association)
|
|
37
39
|
expect(UnusedEagerLoading.send(:diff_object_associations, @post.bullet_key, Set.new([:association]))).to be_empty
|
|
38
40
|
end
|
|
39
41
|
end
|
|
40
42
|
|
|
41
|
-
context
|
|
42
|
-
let(:paths) { [
|
|
43
|
-
it
|
|
43
|
+
context '.check_unused_preload_associations' do
|
|
44
|
+
let(:paths) { ['/dir1', '/dir1/subdir'] }
|
|
45
|
+
it 'should create notification if object_association_diff is not empty' do
|
|
44
46
|
UnusedEagerLoading.add_object_associations(@post, :association)
|
|
45
47
|
allow(UnusedEagerLoading).to receive(:caller_in_project).and_return(paths)
|
|
46
|
-
expect(UnusedEagerLoading).to receive(:create_notification).with(paths,
|
|
48
|
+
expect(UnusedEagerLoading).to receive(:create_notification).with(paths, 'Post', [:association])
|
|
47
49
|
UnusedEagerLoading.check_unused_preload_associations
|
|
48
50
|
end
|
|
49
51
|
|
|
50
|
-
it
|
|
52
|
+
it 'should not create notification if object_association_diff is empty' do
|
|
51
53
|
UnusedEagerLoading.add_object_associations(@post, :association)
|
|
52
54
|
UnusedEagerLoading.add_eager_loadings([@post], :association)
|
|
53
55
|
UnusedEagerLoading.add_call_object_associations(@post, :association)
|
|
54
56
|
expect(UnusedEagerLoading.send(:diff_object_associations, @post.bullet_key, Set.new([:association]))).to be_empty
|
|
55
|
-
expect(UnusedEagerLoading).not_to receive(:create_notification).with(
|
|
57
|
+
expect(UnusedEagerLoading).not_to receive(:create_notification).with('Post', [:association])
|
|
56
58
|
UnusedEagerLoading.check_unused_preload_associations
|
|
57
59
|
end
|
|
58
60
|
end
|
|
59
61
|
|
|
60
|
-
context
|
|
61
|
-
it
|
|
62
|
+
context '.add_eager_loadings' do
|
|
63
|
+
it 'should add objects, associations pair when eager_loadings are empty' do
|
|
62
64
|
UnusedEagerLoading.add_eager_loadings([@post, @post2], :associations)
|
|
63
65
|
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key, @post2.bullet_key], :associations)
|
|
64
66
|
end
|
|
65
67
|
|
|
66
|
-
it
|
|
68
|
+
it 'should add objects, associations pair for existing eager_loadings' do
|
|
67
69
|
UnusedEagerLoading.add_eager_loadings([@post, @post2], :association1)
|
|
68
70
|
UnusedEagerLoading.add_eager_loadings([@post, @post2], :association2)
|
|
69
71
|
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key, @post2.bullet_key], :association1)
|
|
70
72
|
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key, @post2.bullet_key], :association2)
|
|
71
73
|
end
|
|
72
74
|
|
|
73
|
-
it
|
|
75
|
+
it 'should merge objects, associations pair for existing eager_loadings' do
|
|
74
76
|
UnusedEagerLoading.add_eager_loadings([@post], :association1)
|
|
75
77
|
UnusedEagerLoading.add_eager_loadings([@post, @post2], :association2)
|
|
76
78
|
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key], :association1)
|
|
@@ -78,7 +80,7 @@ module Bullet
|
|
|
78
80
|
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post2.bullet_key], :association2)
|
|
79
81
|
end
|
|
80
82
|
|
|
81
|
-
it
|
|
83
|
+
it 'should vmerge objects recursively, associations pair for existing eager_loadings' do
|
|
82
84
|
UnusedEagerLoading.add_eager_loadings([@post, @post2], :association1)
|
|
83
85
|
UnusedEagerLoading.add_eager_loadings([@post, @post3], :association1)
|
|
84
86
|
UnusedEagerLoading.add_eager_loadings([@post, @post3], :association2)
|
|
@@ -89,7 +91,7 @@ module Bullet
|
|
|
89
91
|
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post3.bullet_key], :association2)
|
|
90
92
|
end
|
|
91
93
|
|
|
92
|
-
it
|
|
94
|
+
it 'should delete objects, associations pair for existing eager_loadings' do
|
|
93
95
|
UnusedEagerLoading.add_eager_loadings([@post, @post2], :association1)
|
|
94
96
|
UnusedEagerLoading.add_eager_loadings([@post], :association2)
|
|
95
97
|
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key], :association1)
|
|
@@ -1,36 +1,38 @@
|
|
|
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 namesapce 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 'primary_key_value' do
|
|
21
|
+
it 'should return id' do
|
|
20
22
|
post = Post.first
|
|
21
23
|
expect(post.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
29
|
expect(post.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([
|
|
35
|
+
allow(Post).to receive(:primary_keys).and_return(%i[category_id writer_id])
|
|
34
36
|
expect(post.primary_key_value).to eq("#{post.category_id},#{post.writer_id}")
|
|
35
37
|
end
|
|
36
38
|
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,47 @@
|
|
|
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(
|
|
28
|
+
it 'should leverage ENV parameter' do
|
|
29
|
+
temp_env_variable('USER', 'bogus') do
|
|
30
|
+
expect(subject.whoami).to eq('user: bogus')
|
|
29
31
|
end
|
|
30
32
|
end
|
|
31
33
|
|
|
32
|
-
it
|
|
33
|
-
temp_env_variable(
|
|
34
|
-
expect(subject).to receive(:`).with(
|
|
35
|
-
expect(subject.whoami).to eq(
|
|
34
|
+
it 'should return blank if no user available' do
|
|
35
|
+
temp_env_variable('USER', '') do
|
|
36
|
+
expect(subject).to receive(:`).with('whoami').and_return('')
|
|
37
|
+
expect(subject.whoami).to eq('')
|
|
36
38
|
end
|
|
37
39
|
end
|
|
38
40
|
|
|
39
|
-
it
|
|
40
|
-
temp_env_variable(
|
|
41
|
-
expect(subject).to receive(:`).with(
|
|
42
|
-
expect(subject.whoami).to eq(
|
|
41
|
+
it 'should return blank if whoami is not available' do
|
|
42
|
+
temp_env_variable('USER', '') do
|
|
43
|
+
expect(subject).to receive(:`).with('whoami').and_raise(Errno::ENOENT)
|
|
44
|
+
expect(subject.whoami).to eq('')
|
|
43
45
|
end
|
|
44
46
|
end
|
|
45
47
|
|
|
@@ -50,43 +52,42 @@ module Bullet
|
|
|
50
52
|
ensure
|
|
51
53
|
ENV[name] = old_value
|
|
52
54
|
end
|
|
53
|
-
|
|
54
55
|
end
|
|
55
56
|
|
|
56
|
-
context
|
|
57
|
-
it
|
|
58
|
-
allow(subject).to receive(:body).and_return(
|
|
59
|
-
allow(subject).to receive(:call_stack_messages).and_return(
|
|
57
|
+
context '#body_with_caller' do
|
|
58
|
+
it 'should return body' do
|
|
59
|
+
allow(subject).to receive(:body).and_return('body')
|
|
60
|
+
allow(subject).to receive(:call_stack_messages).and_return('call_stack_messages')
|
|
60
61
|
expect(subject.body_with_caller).to eq("body\ncall_stack_messages\n")
|
|
61
62
|
end
|
|
62
63
|
end
|
|
63
64
|
|
|
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(:
|
|
65
|
+
context '#notification_data' do
|
|
66
|
+
it 'should return notification data' do
|
|
67
|
+
allow(subject).to receive(:whoami).and_return('whoami')
|
|
68
|
+
allow(subject).to receive(:url).and_return('url')
|
|
69
|
+
allow(subject).to receive(:title).and_return('title')
|
|
70
|
+
allow(subject).to receive(:body_with_caller).and_return('body_with_caller')
|
|
71
|
+
expect(subject.notification_data).to eq(user: 'whoami', url: 'url', title: 'title', body: 'body_with_caller')
|
|
71
72
|
end
|
|
72
73
|
end
|
|
73
74
|
|
|
74
|
-
context
|
|
75
|
-
it
|
|
75
|
+
context '#notify_inline' do
|
|
76
|
+
it 'should send full_notice to notifier' do
|
|
76
77
|
notifier = double
|
|
77
78
|
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(:
|
|
79
|
+
allow(subject).to receive(:notification_data).and_return(foo: :bar)
|
|
80
|
+
expect(notifier).to receive(:inline_notify).with(foo: :bar)
|
|
80
81
|
subject.notify_inline
|
|
81
82
|
end
|
|
82
83
|
end
|
|
83
84
|
|
|
84
|
-
context
|
|
85
|
-
it
|
|
85
|
+
context '#notify_out_of_channel' do
|
|
86
|
+
it 'should send full_out_of_channel to notifier' do
|
|
86
87
|
notifier = double
|
|
87
88
|
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(:
|
|
89
|
+
allow(subject).to receive(:notification_data).and_return(foo: :bar)
|
|
90
|
+
expect(notifier).to receive(:out_of_channel_notify).with(foo: :bar)
|
|
90
91
|
subject.notify_out_of_channel
|
|
91
92
|
end
|
|
92
93
|
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,16 @@
|
|
|
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
10
|
it { expect(subject.body_with_caller).to eq(" Post => [:comments, :votes]\n Add to your finder: :includes => [:comments, :votes]\nCall stack\n caller1\n caller2\n") }
|
|
9
|
-
it { expect([subject.body_with_caller, subject.body_with_caller]).to eq([
|
|
11
|
+
it { expect([subject.body_with_caller, subject.body_with_caller]).to eq([" Post => [:comments, :votes]\n Add to your finder: :includes => [:comments, :votes]\nCall stack\n caller1\n caller2\n", " Post => [:comments, :votes]\n Add to your finder: :includes => [:comments, :votes]\nCall stack\n caller1\n caller2\n"]) }
|
|
10
12
|
it { expect(subject.body).to eq(" Post => [:comments, :votes]\n Add to your finder: :includes => [:comments, :votes]") }
|
|
11
|
-
it { expect(subject.title).to eq(
|
|
13
|
+
it { expect(subject.title).to eq('USE eager loading in path') }
|
|
12
14
|
end
|
|
13
15
|
end
|
|
14
16
|
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 UnusedEagerLoading do
|
|
6
|
-
subject { UnusedEagerLoading.new([
|
|
8
|
+
subject { UnusedEagerLoading.new([''], Post, %i[comments votes], 'path') }
|
|
7
9
|
|
|
8
10
|
it { expect(subject.body).to eq(" Post => [:comments, :votes]\n Remove from your finder: :includes => [:comments, :votes]") }
|
|
9
|
-
it { expect(subject.title).to eq(
|
|
11
|
+
it { expect(subject.title).to eq('AVOID eager loading in path') }
|
|
10
12
|
end
|
|
11
13
|
end
|
|
12
14
|
end
|
|
@@ -1,29 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'spec_helper'
|
|
2
4
|
|
|
3
5
|
module Bullet
|
|
4
6
|
describe NotificationCollector do
|
|
5
|
-
subject { NotificationCollector.new.tap { |collector| collector.add(
|
|
7
|
+
subject { NotificationCollector.new.tap { |collector| collector.add('value') } }
|
|
6
8
|
|
|
7
|
-
context
|
|
8
|
-
it
|
|
9
|
-
subject.add(
|
|
10
|
-
expect(subject.collection).to be_include(
|
|
9
|
+
context '#add' do
|
|
10
|
+
it 'should add a value' do
|
|
11
|
+
subject.add('value1')
|
|
12
|
+
expect(subject.collection).to be_include('value1')
|
|
11
13
|
end
|
|
12
14
|
end
|
|
13
15
|
|
|
14
|
-
context
|
|
15
|
-
it
|
|
16
|
+
context '#reset' do
|
|
17
|
+
it 'should reset collector' do
|
|
16
18
|
subject.reset
|
|
17
19
|
expect(subject.collection).to be_empty
|
|
18
20
|
end
|
|
19
21
|
end
|
|
20
22
|
|
|
21
|
-
context
|
|
22
|
-
it
|
|
23
|
+
context '#notifications_present?' do
|
|
24
|
+
it 'should be true if collection is not empty' do
|
|
23
25
|
expect(subject).to be_notifications_present
|
|
24
26
|
end
|
|
25
27
|
|
|
26
|
-
it
|
|
28
|
+
it 'should be false if collection is empty' do
|
|
27
29
|
subject.reset
|
|
28
30
|
expect(subject).not_to be_notifications_present
|
|
29
31
|
end
|