bullet 5.9.0 → 6.1.1
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/.travis.yml +22 -1
- data/CHANGELOG.md +27 -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 +1 -1
- data/Gemfile.rails-5.1 +1 -1
- data/Gemfile.rails-5.2 +1 -1
- data/Gemfile.rails-6.0 +15 -0
- data/Gemfile.rails-6.1 +15 -0
- data/README.md +31 -10
- data/lib/bullet.rb +50 -26
- data/lib/bullet/active_job.rb +13 -0
- data/lib/bullet/active_record4.rb +9 -32
- data/lib/bullet/active_record41.rb +7 -27
- data/lib/bullet/active_record42.rb +8 -24
- data/lib/bullet/active_record5.rb +188 -179
- data/lib/bullet/active_record52.rb +176 -168
- data/lib/bullet/active_record60.rb +267 -0
- data/lib/bullet/active_record61.rb +267 -0
- data/lib/bullet/bullet_xhr.js +63 -0
- data/lib/bullet/dependency.rb +50 -36
- data/lib/bullet/detector/association.rb +26 -20
- data/lib/bullet/detector/base.rb +1 -2
- data/lib/bullet/detector/counter_cache.rb +13 -9
- data/lib/bullet/detector/n_plus_one_query.rb +22 -12
- data/lib/bullet/detector/unused_eager_loading.rb +6 -3
- data/lib/bullet/ext/object.rb +4 -2
- data/lib/bullet/mongoid4x.rb +2 -6
- data/lib/bullet/mongoid5x.rb +2 -6
- data/lib/bullet/mongoid6x.rb +2 -6
- data/lib/bullet/mongoid7x.rb +2 -6
- data/lib/bullet/notification/base.rb +14 -18
- data/lib/bullet/notification/n_plus_one_query.rb +2 -4
- data/lib/bullet/notification/unused_eager_loading.rb +2 -4
- data/lib/bullet/rack.rb +50 -25
- data/lib/bullet/stack_trace_filter.rb +6 -12
- data/lib/bullet/version.rb +1 -1
- data/lib/generators/bullet/install_generator.rb +23 -23
- data/perf/benchmark.rb +8 -14
- data/spec/bullet/detector/counter_cache_spec.rb +6 -6
- data/spec/bullet/detector/n_plus_one_query_spec.rb +7 -3
- data/spec/bullet/detector/unused_eager_loading_spec.rb +19 -6
- data/spec/bullet/ext/object_spec.rb +9 -4
- data/spec/bullet/notification/base_spec.rb +1 -3
- data/spec/bullet/notification/n_plus_one_query_spec.rb +16 -3
- data/spec/bullet/notification/unused_eager_loading_spec.rb +5 -1
- data/spec/bullet/rack_spec.rb +86 -6
- data/spec/bullet/registry/association_spec.rb +2 -2
- data/spec/bullet/registry/base_spec.rb +1 -1
- data/spec/bullet_spec.rb +11 -30
- data/spec/integration/active_record/association_spec.rb +44 -136
- data/spec/integration/counter_cache_spec.rb +11 -31
- data/spec/integration/mongoid/association_spec.rb +18 -32
- data/spec/models/folder.rb +1 -2
- data/spec/models/group.rb +1 -2
- data/spec/models/page.rb +1 -2
- data/spec/models/writer.rb +1 -2
- data/spec/spec_helper.rb +6 -10
- data/spec/support/bullet_ext.rb +8 -9
- data/spec/support/mongo_seed.rb +2 -16
- data/test.sh +1 -0
- metadata +12 -7
@@ -5,12 +5,12 @@ module Bullet
|
|
5
5
|
VENDOR_PATH = '/vendor'
|
6
6
|
|
7
7
|
def caller_in_project
|
8
|
-
|
9
|
-
vendor_root = app_root + VENDOR_PATH
|
8
|
+
vendor_root = Bullet.app_root + VENDOR_PATH
|
10
9
|
bundler_path = Bundler.bundle_path.to_s
|
11
10
|
select_caller_locations do |location|
|
12
11
|
caller_path = location_as_path(location)
|
13
|
-
caller_path.include?(app_root) && !caller_path.include?(vendor_root) &&
|
12
|
+
caller_path.include?(Bullet.app_root) && !caller_path.include?(vendor_root) &&
|
13
|
+
!caller_path.include?(bundler_path) ||
|
14
14
|
Bullet.stacktrace_includes.any? { |include_pattern| pattern_matches?(location, include_pattern) }
|
15
15
|
end
|
16
16
|
end
|
@@ -52,20 +52,14 @@ module Bullet
|
|
52
52
|
|
53
53
|
def select_caller_locations
|
54
54
|
if ruby_19?
|
55
|
-
caller.select
|
56
|
-
yield caller_path
|
57
|
-
end
|
55
|
+
caller.select { |caller_path| yield caller_path }
|
58
56
|
else
|
59
|
-
caller_locations.select
|
60
|
-
yield location
|
61
|
-
end
|
57
|
+
caller_locations.select { |location| yield location }
|
62
58
|
end
|
63
59
|
end
|
64
60
|
|
65
61
|
def ruby_19?
|
66
|
-
if @ruby_19.nil?
|
67
|
-
@ruby_19 = Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0')
|
68
|
-
end
|
62
|
+
@ruby_19 = Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0') if @ruby_19.nil?
|
69
63
|
@ruby_19
|
70
64
|
end
|
71
65
|
end
|
data/lib/bullet/version.rb
CHANGED
@@ -10,17 +10,17 @@ module Bullet
|
|
10
10
|
|
11
11
|
def enable_in_development
|
12
12
|
environment(nil, env: 'development') do
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
13
|
+
<<~FILE
|
14
|
+
config.after_initialize do
|
15
|
+
Bullet.enable = true
|
16
|
+
Bullet.alert = true
|
17
|
+
Bullet.bullet_logger = true
|
18
|
+
Bullet.console = true
|
19
|
+
# Bullet.growl = true
|
20
|
+
Bullet.rails_logger = true
|
21
|
+
Bullet.add_footer = true
|
22
|
+
end
|
23
|
+
|
24
24
|
FILE
|
25
25
|
end
|
26
26
|
|
@@ -28,20 +28,20 @@ module Bullet
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def enable_in_test
|
31
|
-
|
32
|
-
environment(nil, env: 'test') do
|
33
|
-
<<-"FILE".strip
|
34
|
-
|
35
|
-
config.after_initialize do
|
36
|
-
Bullet.enable = true
|
37
|
-
Bullet.bullet_logger = true
|
38
|
-
Bullet.raise = true # raise an error if n+1 query occurs
|
39
|
-
end
|
40
|
-
FILE
|
41
|
-
end
|
31
|
+
return unless yes?('Would you like to enable bullet in test environment? (y/n)')
|
42
32
|
|
43
|
-
|
33
|
+
environment(nil, env: 'test') do
|
34
|
+
<<~FILE
|
35
|
+
config.after_initialize do
|
36
|
+
Bullet.enable = true
|
37
|
+
Bullet.bullet_logger = true
|
38
|
+
Bullet.raise = true # raise an error if n+1 query occurs
|
39
|
+
end
|
40
|
+
|
41
|
+
FILE
|
44
42
|
end
|
43
|
+
|
44
|
+
say 'Enabled bullet in config/environments/test.rb'
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
data/perf/benchmark.rb
CHANGED
@@ -29,11 +29,11 @@ class User < ActiveRecord::Base
|
|
29
29
|
end
|
30
30
|
|
31
31
|
# create database bullet_benchmark;
|
32
|
-
ActiveRecord::Base.establish_connection(
|
32
|
+
ActiveRecord::Base.establish_connection(
|
33
|
+
adapter: 'mysql2', database: 'bullet_benchmark', server: '/tmp/mysql.socket', username: 'root'
|
34
|
+
)
|
33
35
|
|
34
|
-
ActiveRecord::Base.connection.tables.each
|
35
|
-
ActiveRecord::Base.connection.drop_table(table)
|
36
|
-
end
|
36
|
+
ActiveRecord::Base.connection.tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
|
37
37
|
|
38
38
|
ActiveRecord::Schema.define(version: 1) do
|
39
39
|
create_table :posts do |t|
|
@@ -54,26 +54,20 @@ ActiveRecord::Schema.define(version: 1) do
|
|
54
54
|
end
|
55
55
|
|
56
56
|
users_size = 100
|
57
|
-
posts_size =
|
57
|
+
posts_size = 1_000
|
58
58
|
comments_size = 10_000
|
59
59
|
users = []
|
60
|
-
users_size.times
|
61
|
-
users << User.new(name: "user#{i}")
|
62
|
-
end
|
60
|
+
users_size.times { |i| users << User.new(name: "user#{i}") }
|
63
61
|
User.import users
|
64
62
|
users = User.all
|
65
63
|
|
66
64
|
posts = []
|
67
|
-
posts_size.times
|
68
|
-
posts << Post.new(title: "Title #{i}", body: "Body #{i}", user: users[i % 100])
|
69
|
-
end
|
65
|
+
posts_size.times { |i| posts << Post.new(title: "Title #{i}", body: "Body #{i}", user: users[i % 100]) }
|
70
66
|
Post.import posts
|
71
67
|
posts = Post.all
|
72
68
|
|
73
69
|
comments = []
|
74
|
-
comments_size.times
|
75
|
-
comments << Comment.new(body: "Comment #{i}", post: posts[i % 1000], user: users[i % 100])
|
76
|
-
end
|
70
|
+
comments_size.times { |i| comments << Comment.new(body: "Comment #{i}", post: posts[i % 1_000], user: users[i % 100]) }
|
77
71
|
Comment.import comments
|
78
72
|
|
79
73
|
puts 'Start benchmarking...'
|
@@ -12,15 +12,15 @@ module Bullet
|
|
12
12
|
|
13
13
|
context '.add_counter_cache' do
|
14
14
|
it 'should create notification if conditions met' do
|
15
|
-
expect(CounterCache).to receive(:conditions_met?).with(@post1, [
|
16
|
-
expect(CounterCache).to receive(:create_notification).with('Post', [
|
17
|
-
CounterCache.add_counter_cache(@post1, [
|
15
|
+
expect(CounterCache).to receive(:conditions_met?).with(@post1, %i[comments]).and_return(true)
|
16
|
+
expect(CounterCache).to receive(:create_notification).with('Post', %i[comments])
|
17
|
+
CounterCache.add_counter_cache(@post1, %i[comments])
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'should not create notification if conditions not met' do
|
21
|
-
expect(CounterCache).to receive(:conditions_met?).with(@post1, [
|
21
|
+
expect(CounterCache).to receive(:conditions_met?).with(@post1, %i[comments]).and_return(false)
|
22
22
|
expect(CounterCache).to receive(:create_notification).never
|
23
|
-
CounterCache.add_counter_cache(@post1, [
|
23
|
+
CounterCache.add_counter_cache(@post1, %i[comments])
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
@@ -47,7 +47,7 @@ module Bullet
|
|
47
47
|
expect(CounterCache.conditions_met?(@post1, :associations)).to eq false
|
48
48
|
end
|
49
49
|
|
50
|
-
it 'should be
|
50
|
+
it 'should be false when object is possible, and impossible' do
|
51
51
|
CounterCache.add_possible_objects(@post1)
|
52
52
|
CounterCache.add_impossible_object(@post1)
|
53
53
|
expect(CounterCache.conditions_met?(@post1, :associations)).to eq false
|
@@ -76,8 +76,8 @@ module Bullet
|
|
76
76
|
context '.call_association' do
|
77
77
|
it 'should create notification if conditions met' do
|
78
78
|
expect(NPlusOneQuery).to receive(:conditions_met?).with(@post, :association).and_return(true)
|
79
|
-
expect(NPlusOneQuery).to receive(:caller_in_project).and_return([
|
80
|
-
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)
|
81
81
|
NPlusOneQuery.call_association(@post, :association)
|
82
82
|
end
|
83
83
|
|
@@ -149,7 +149,11 @@ module Bullet
|
|
149
149
|
|
150
150
|
expect(NPlusOneQuery).to receive(:caller_locations).and_return([in_project, *included_gems, excluded_gem])
|
151
151
|
expect(NPlusOneQuery).to receive(:conditions_met?).with(@post, :association).and_return(true)
|
152
|
-
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
|
+
)
|
153
157
|
NPlusOneQuery.call_association(@post, :association)
|
154
158
|
end
|
155
159
|
end
|
@@ -36,12 +36,14 @@ module Bullet
|
|
36
36
|
it 'should return empty if associations exist in call_association' do
|
37
37
|
UnusedEagerLoading.add_eager_loadings([@post], :association)
|
38
38
|
UnusedEagerLoading.add_call_object_associations(@post, :association)
|
39
|
-
expect(
|
39
|
+
expect(
|
40
|
+
UnusedEagerLoading.send(:diff_object_associations, @post.bullet_key, Set.new([:association]))
|
41
|
+
).to be_empty
|
40
42
|
end
|
41
43
|
end
|
42
44
|
|
43
45
|
context '.check_unused_preload_associations' do
|
44
|
-
let(:paths) { [
|
46
|
+
let(:paths) { %w[/dir1 /dir1/subdir] }
|
45
47
|
it 'should create notification if object_association_diff is not empty' do
|
46
48
|
UnusedEagerLoading.add_object_associations(@post, :association)
|
47
49
|
allow(UnusedEagerLoading).to receive(:caller_in_project).and_return(paths)
|
@@ -53,7 +55,9 @@ module Bullet
|
|
53
55
|
UnusedEagerLoading.add_object_associations(@post, :association)
|
54
56
|
UnusedEagerLoading.add_eager_loadings([@post], :association)
|
55
57
|
UnusedEagerLoading.add_call_object_associations(@post, :association)
|
56
|
-
expect(
|
58
|
+
expect(
|
59
|
+
UnusedEagerLoading.send(:diff_object_associations, @post.bullet_key, Set.new([:association]))
|
60
|
+
).to be_empty
|
57
61
|
expect(UnusedEagerLoading).not_to receive(:create_notification).with('Post', [:association])
|
58
62
|
UnusedEagerLoading.check_unused_preload_associations
|
59
63
|
end
|
@@ -62,14 +66,23 @@ module Bullet
|
|
62
66
|
context '.add_eager_loadings' do
|
63
67
|
it 'should add objects, associations pair when eager_loadings are empty' do
|
64
68
|
UnusedEagerLoading.add_eager_loadings([@post, @post2], :associations)
|
65
|
-
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include(
|
69
|
+
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include(
|
70
|
+
[@post.bullet_key, @post2.bullet_key],
|
71
|
+
:associations
|
72
|
+
)
|
66
73
|
end
|
67
74
|
|
68
75
|
it 'should add objects, associations pair for existing eager_loadings' do
|
69
76
|
UnusedEagerLoading.add_eager_loadings([@post, @post2], :association1)
|
70
77
|
UnusedEagerLoading.add_eager_loadings([@post, @post2], :association2)
|
71
|
-
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include(
|
72
|
-
|
78
|
+
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include(
|
79
|
+
[@post.bullet_key, @post2.bullet_key],
|
80
|
+
:association1
|
81
|
+
)
|
82
|
+
expect(UnusedEagerLoading.send(:eager_loadings)).to be_include(
|
83
|
+
[@post.bullet_key, @post2.bullet_key],
|
84
|
+
:association2
|
85
|
+
)
|
73
86
|
end
|
74
87
|
|
75
88
|
it 'should merge objects, associations pair for existing eager_loadings' do
|
@@ -17,23 +17,28 @@ describe Object do
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
context '
|
20
|
+
context 'bullet_primary_key_value' do
|
21
21
|
it 'should return id' do
|
22
22
|
post = Post.first
|
23
|
-
expect(post.
|
23
|
+
expect(post.bullet_primary_key_value).to eq(post.id)
|
24
24
|
end
|
25
25
|
|
26
26
|
it 'should return primary key value' do
|
27
27
|
post = Post.first
|
28
28
|
Post.primary_key = 'name'
|
29
|
-
expect(post.
|
29
|
+
expect(post.bullet_primary_key_value).to eq(post.name)
|
30
30
|
Post.primary_key = 'id'
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'should return value for multiple primary keys' do
|
34
34
|
post = Post.first
|
35
35
|
allow(Post).to receive(:primary_keys).and_return(%i[category_id writer_id])
|
36
|
-
expect(post.
|
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
|
37
42
|
end
|
38
43
|
end
|
39
44
|
end
|
@@ -26,9 +26,7 @@ module Bullet
|
|
26
26
|
end
|
27
27
|
|
28
28
|
it 'should leverage ENV parameter' do
|
29
|
-
temp_env_variable('USER', 'bogus')
|
30
|
-
expect(subject.whoami).to eq('user: bogus')
|
31
|
-
end
|
29
|
+
temp_env_variable('USER', 'bogus') { expect(subject.whoami).to eq('user: bogus') }
|
32
30
|
end
|
33
31
|
|
34
32
|
it 'should return blank if no user available' do
|
@@ -7,9 +7,22 @@ module Bullet
|
|
7
7
|
describe NPlusOneQuery do
|
8
8
|
subject { NPlusOneQuery.new([%w[caller1 caller2]], Post, %i[comments votes], 'path') }
|
9
9
|
|
10
|
-
it
|
11
|
-
|
12
|
-
|
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
|
13
26
|
it { expect(subject.title).to eq('USE eager loading in path') }
|
14
27
|
end
|
15
28
|
end
|
@@ -7,7 +7,11 @@ module Bullet
|
|
7
7
|
describe UnusedEagerLoading do
|
8
8
|
subject { UnusedEagerLoading.new([''], Post, %i[comments votes], 'path') }
|
9
9
|
|
10
|
-
it
|
10
|
+
it do
|
11
|
+
expect(subject.body).to eq(
|
12
|
+
" Post => [:comments, :votes]\n Remove from your query: .includes([:comments, :votes])"
|
13
|
+
)
|
14
|
+
end
|
11
15
|
it { expect(subject.title).to eq('AVOID eager loading in path') }
|
12
16
|
end
|
13
17
|
end
|
data/spec/bullet/rack_spec.rb
CHANGED
@@ -45,9 +45,9 @@ module Bullet
|
|
45
45
|
expect(middleware).not_to be_empty(response)
|
46
46
|
end
|
47
47
|
|
48
|
-
it 'should be
|
48
|
+
it 'should be false if response is not found' do
|
49
49
|
response = ['Not Found']
|
50
|
-
expect(middleware).
|
50
|
+
expect(middleware).not_to be_empty(response)
|
51
51
|
end
|
52
52
|
|
53
53
|
it 'should be true if response body is empty' do
|
@@ -67,11 +67,13 @@ module Bullet
|
|
67
67
|
|
68
68
|
it 'should change response body if notification is active' do
|
69
69
|
expect(Bullet).to receive(:notification?).and_return(true)
|
70
|
+
expect(Bullet).to receive(:console_enabled?).and_return(true)
|
70
71
|
expect(Bullet).to receive(:gather_inline_notifications).and_return('<bullet></bullet>')
|
72
|
+
expect(middleware).to receive(:xhr_script).and_return('')
|
71
73
|
expect(Bullet).to receive(:perform_out_of_channel_notifications)
|
72
|
-
|
74
|
+
_, headers, response = middleware.call('Content-Type' => 'text/html')
|
73
75
|
expect(headers['Content-Length']).to eq('56')
|
74
|
-
expect(response).to eq([
|
76
|
+
expect(response).to eq(%w[<html><head></head><body><bullet></bullet></body></html>])
|
75
77
|
end
|
76
78
|
|
77
79
|
it 'should set the right Content-Length if response body contains accents' do
|
@@ -79,9 +81,79 @@ module Bullet
|
|
79
81
|
response.body = '<html><head></head><body>é</body></html>'
|
80
82
|
app.response = response
|
81
83
|
expect(Bullet).to receive(:notification?).and_return(true)
|
84
|
+
allow(Bullet).to receive(:console_enabled?).and_return(true)
|
82
85
|
expect(Bullet).to receive(:gather_inline_notifications).and_return('<bullet></bullet>')
|
83
|
-
|
84
|
-
expect(headers['Content-Length']).to eq(
|
86
|
+
_, headers, response = middleware.call('Content-Type' => 'text/html')
|
87
|
+
expect(headers['Content-Length']).to eq((58 + middleware.send(:xhr_script).length).to_s)
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'with injection notifiers' do
|
91
|
+
before do
|
92
|
+
expect(Bullet).to receive(:notification?).and_return(true)
|
93
|
+
allow(Bullet).to receive(:gather_inline_notifications).and_return('<bullet></bullet>')
|
94
|
+
allow(middleware).to receive(:xhr_script).and_return('')
|
95
|
+
allow(middleware).to receive(:footer_note).and_return('footer')
|
96
|
+
expect(Bullet).to receive(:perform_out_of_channel_notifications)
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should change response body if add_footer is true' do
|
100
|
+
expect(Bullet).to receive(:add_footer).twice.and_return(true)
|
101
|
+
_, headers, response = middleware.call('Content-Type' => 'text/html')
|
102
|
+
|
103
|
+
expect(headers['Content-Length']).to eq((56 + middleware.send(:footer_note).length).to_s)
|
104
|
+
expect(response.first).to start_with('<html><head></head><body>')
|
105
|
+
expect(response.first).to include('<bullet></bullet><')
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should change response body for html safe string if add_footer is true' do
|
109
|
+
expect(Bullet).to receive(:add_footer).twice.and_return(true)
|
110
|
+
app.response = Support::ResponseDouble.new.tap do |response|
|
111
|
+
response.body = ActiveSupport::SafeBuffer.new('<html><head></head><body></body></html>')
|
112
|
+
end
|
113
|
+
_, headers, response = middleware.call('Content-Type' => 'text/html')
|
114
|
+
|
115
|
+
expect(headers['Content-Length']).to eq((56 + middleware.send(:footer_note).length).to_s)
|
116
|
+
expect(response.first).to start_with('<html><head></head><body>')
|
117
|
+
expect(response.first).to include('<bullet></bullet><')
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'should change response body if console_enabled is true' do
|
121
|
+
expect(Bullet).to receive(:console_enabled?).and_return(true)
|
122
|
+
_, headers, response = middleware.call('Content-Type' => 'text/html')
|
123
|
+
expect(headers['Content-Length']).to eq('56')
|
124
|
+
expect(response).to eq(%w[<html><head></head><body><bullet></bullet></body></html>])
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should change response body for html safe string if console_enabled is true' do
|
128
|
+
expect(Bullet).to receive(:console_enabled?).and_return(true)
|
129
|
+
app.response = Support::ResponseDouble.new.tap do |response|
|
130
|
+
response.body = ActiveSupport::SafeBuffer.new('<html><head></head><body></body></html>')
|
131
|
+
end
|
132
|
+
_, headers, response = middleware.call('Content-Type' => 'text/html')
|
133
|
+
expect(headers['Content-Length']).to eq('56')
|
134
|
+
expect(response).to eq(%w[<html><head></head><body><bullet></bullet></body></html>])
|
135
|
+
end
|
136
|
+
|
137
|
+
it "shouldn't change response body unnecessarily" do
|
138
|
+
expected_response = Support::ResponseDouble.new 'Actual body'
|
139
|
+
app.response = expected_response
|
140
|
+
_, _, response = middleware.call({})
|
141
|
+
expect(response).to eq(expected_response)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context 'when skip_html_injection is enabled' do
|
146
|
+
it 'should not try to inject html' do
|
147
|
+
expected_response = Support::ResponseDouble.new 'Actual body'
|
148
|
+
app.response = expected_response
|
149
|
+
allow(Bullet).to receive(:notification?).and_return(true)
|
150
|
+
allow(Bullet).to receive(:skip_html_injection?).and_return(true)
|
151
|
+
expect(Bullet).to receive(:gather_inline_notifications).never
|
152
|
+
expect(middleware).to receive(:xhr_script).never
|
153
|
+
expect(Bullet).to receive(:perform_out_of_channel_notifications)
|
154
|
+
_, _, response = middleware.call('Content-Type' => 'text/html')
|
155
|
+
expect(response).to eq(expected_response)
|
156
|
+
end
|
85
157
|
end
|
86
158
|
end
|
87
159
|
|
@@ -95,6 +167,14 @@ module Bullet
|
|
95
167
|
end
|
96
168
|
end
|
97
169
|
|
170
|
+
context '#set_header' do
|
171
|
+
it 'should truncate headers to under 8kb' do
|
172
|
+
long_header = ['a' * 1_024] * 10
|
173
|
+
expected_res = (['a' * 1_024] * 7).to_json
|
174
|
+
expect(middleware.set_header({}, 'Dummy-Header', long_header)).to eq(expected_res)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
98
178
|
describe '#response_body' do
|
99
179
|
let(:response) { double }
|
100
180
|
let(:body_string) { '<html><body>My Body</body></html>' }
|