/
rack_logger_test.rb
150 lines (124 loc) · 4.87 KB
/
rack_logger_test.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# frozen_string_literal: true
require "abstract_unit"
require "active_support/testing/autorun"
require "active_support/test_case"
require "rails/rack/logger"
require "logger"
require "active_support/log_subscriber/test_helper"
module Rails
module Rack
class LoggerTest < ActiveSupport::TestCase
include ActiveSupport::LogSubscriber::TestHelper
class TestLogger < Rails::Rack::Logger
NULL = ::Logger.new File::NULL
attr_reader :logger
def initialize(logger = NULL, app: nil, taggers: nil, &block)
app ||= ->(_) { block.call; [200, {}, []] }
super(app, taggers)
@logger = logger
end
def development?; false; end
end
class TestApp < Struct.new(:response)
def call(_env)
response
end
end
Subscriber = Struct.new(:starts, :finishes) do
def initialize(starts = [], finishes = [])
super
end
def start(name, id, payload)
starts << [name, id, payload]
end
def finish(name, id, payload)
finishes << [name, id, payload]
end
end
attr_reader :subscriber
def setup
super
@subscriber = Subscriber.new
@subscription = ActiveSupport::Notifications.notifier.subscribe "request.action_dispatch", subscriber
end
def teardown
ActiveSupport::Notifications.notifier.unsubscribe @subscription
end
def test_notification
logger = TestLogger.new { }
assert_difference("subscriber.starts.length") do
assert_difference("subscriber.finishes.length") do
logger.call("REQUEST_METHOD" => "GET").last.close
end
end
end
def test_notification_on_raise
logger = TestLogger.new do
# using an exception class that is not a StandardError subclass on purpose
raise NotImplementedError
end
assert_difference("subscriber.starts.length") do
assert_difference("subscriber.finishes.length") do
assert_raises(NotImplementedError) do
logger.call "REQUEST_METHOD" => "GET"
end
end
end
end
def test_logger_does_not_mutate_app_return
response = [].freeze
app = TestApp.new(response)
logger = TestLogger.new(app: app)
assert_no_changes("response") do
assert_nothing_raised do
logger.call("REQUEST_METHOD" => "GET")
end
end
end
def test_logger_is_flushed_after_request_finished
logger_middleware = TestLogger.new { }
flush_count_in_request_event = nil
block_sub = @notifier.subscribe "request.action_dispatch" do |_event|
flush_count_in_request_event = ActiveSupport::LogSubscriber.logger.flush_count
end
# Assert that we don't get a logger flush when we finish the response headers
response_body = nil
assert_no_difference("ActiveSupport::LogSubscriber.logger.flush_count") do
response_body = logger_middleware.call("REQUEST_METHOD" => "GET").last
end
# Assert that we _do_ get a logger flush when we finish the response body
assert_difference("ActiveSupport::LogSubscriber.logger.flush_count") do
response_body.close
end
# And that the flush happens _after_ any LogSubscribers etc get run.
flush_count = ActiveSupport::LogSubscriber.logger.flush_count
assert_equal(1, flush_count - flush_count_in_request_event, "flush_all! should happen after event")
ensure
@notifier.unsubscribe block_sub
end
def test_logger_pushes_tags
@logger = ActiveSupport::TaggedLogging.new(@logger)
set_logger(@logger)
taggers = ["tag1", ->(_req) { "tag2" }]
logger_middleware = TestLogger.new(@logger, taggers: taggers) do
# We can't really assert on logging something with the tags, because the MockLogger implementation
# does not call the formatter (which is responsible for appending the tags)
assert_equal(["tag1", "tag2"], @logger.formatter.current_tags)
end
block_sub = @notifier.subscribe "request.action_dispatch" do |_event|
assert_equal(["tag1", "tag2"], @logger.formatter.current_tags)
end
# Call the app - it should log the inside app message
response_body = logger_middleware.call("REQUEST_METHOD" => "GET").last
# The tags should still be open as long as the request body isn't closed
assert_equal(["tag1", "tag2"], @logger.formatter.current_tags)
# And now should fire the request.action_dispatch event and call the event handler
response_body.close
# And it should also clear the tag stack.
assert_equal([], @logger.formatter.current_tags)
ensure
@notifier.unsubscribe block_sub
end
end
end
end