marlowe 1.0.3 → 3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/ruby.yml +55 -0
- data/.standard.yml +4 -0
- data/Contributing.md +71 -0
- data/History.md +43 -0
- data/Licence.md +25 -0
- data/Manifest.txt +8 -4
- data/README.rdoc +168 -50
- data/Rakefile +51 -44
- data/lib/marlowe/config.rb +116 -0
- data/lib/marlowe/faraday.rb +20 -0
- data/lib/marlowe/formatter.rb +4 -4
- data/lib/marlowe/middleware.rb +50 -20
- data/lib/marlowe/rails.rb +20 -5
- data/lib/marlowe/simple_formatter.rb +3 -4
- data/lib/marlowe.rb +40 -5
- data/test/minitest_config.rb +8 -19
- data/test/test_marlowe.rb +90 -19
- data/test/test_marlowe_config.rb +109 -0
- metadata +127 -64
- data/.autotest +0 -25
- data/Gemfile +0 -9
- data/History.rdoc +0 -17
- data/Licence.rdoc +0 -27
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Configuration object for Marlowe.
|
4
|
+
class Marlowe::Config
|
5
|
+
# The name of the default header to look for and put the correlation id in.
|
6
|
+
CORRELATION_HEADER = "X-Request-Id" # :nodoc:
|
7
|
+
|
8
|
+
class << self
|
9
|
+
# The global Marlowe configuration.
|
10
|
+
def global
|
11
|
+
@global ||= new
|
12
|
+
end
|
13
|
+
|
14
|
+
# Override the global Marlowe configuration.
|
15
|
+
def override(opts)
|
16
|
+
new(global, opts)
|
17
|
+
end
|
18
|
+
|
19
|
+
def configure(&block) # :nodoc:
|
20
|
+
@global = new(global, &block)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def clear_global!
|
26
|
+
@global = nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# The name of the header to inspect. Defaults to 'X-Request-Id'.
|
31
|
+
attr_accessor :header
|
32
|
+
# The HTTP formatted version of the header name to inspect. Defaults to
|
33
|
+
# 'HTTP_X_REQUEST_ID'.
|
34
|
+
attr_reader :http_header
|
35
|
+
# The handler for request correlation IDs. Defaults to sanitizing provided
|
36
|
+
# request IDs or generating a UUID. If <tt>:simple</tt> is provided, provided
|
37
|
+
# request IDs will not be sanitized. A callable (expecting a single input of
|
38
|
+
# any possible existing request ID) may be provided to introduce more complex
|
39
|
+
# request ID handling.
|
40
|
+
attr_accessor :handler
|
41
|
+
# If +true+ (the default), the request correlation ID will be returned as
|
42
|
+
# part of the response headers. Only affects Marlowe::Middleware.
|
43
|
+
attr_accessor :return
|
44
|
+
# If +true+, Marlowe will add code to behave like
|
45
|
+
# <tt>ActionDispatch::RequestId</tt>. Depends on
|
46
|
+
# <tt>ActionDispatch::Request</tt>. Only affects Marlowe::Middleware.
|
47
|
+
attr_accessor :action_dispatch
|
48
|
+
|
49
|
+
# === Option Values
|
50
|
+
#
|
51
|
+
# <tt>:header</tt>:: The name of the header to inspect. Defaults to
|
52
|
+
# 'X-Request-Id'. Also available as
|
53
|
+
# <tt>:correlation_header</tt>.
|
54
|
+
# <tt>:handler</tt>:: The handler for request correlation IDs. Defaults to
|
55
|
+
# sanitizing provided request IDs or generating a UUID.
|
56
|
+
# If <tt>:simple</tt> is provided, provided request IDs
|
57
|
+
# will not be sanitized. A callable (expecting a single
|
58
|
+
# input of any possible existing request ID) may be
|
59
|
+
# provided to introduce more complex request ID
|
60
|
+
# handling.
|
61
|
+
# <tt>:return</tt>:: If +true+ (the default), the request correlation ID
|
62
|
+
# will be returned as part of the response headers.
|
63
|
+
# <tt>:action_dispatch</tt>:: If +true+, Marlowe will add code to behave
|
64
|
+
# like <tt>ActionDispatch::RequestId</tt>.
|
65
|
+
# Depends on <tt>ActionDispatch::Request</tt>.
|
66
|
+
def initialize(base = nil, opts = nil) # :yields: self
|
67
|
+
opts =
|
68
|
+
if base.nil? && opts.nil?
|
69
|
+
{}
|
70
|
+
elsif base.nil? && opts.is_a?(Hash)
|
71
|
+
opts
|
72
|
+
elsif base.is_a?(Hash) && opts.nil?
|
73
|
+
base
|
74
|
+
elsif base.is_a?(self.class) && opts.nil?
|
75
|
+
base.to_hash
|
76
|
+
elsif (base.is_a?(Hash) || base.is_a?(self.class)) && opts.is_a?(Hash)
|
77
|
+
hash =
|
78
|
+
if base.is_a?(self.class)
|
79
|
+
base.to_hash
|
80
|
+
else
|
81
|
+
base
|
82
|
+
end
|
83
|
+
hash.update(opts)
|
84
|
+
end
|
85
|
+
|
86
|
+
@header, @http_header = format_header_name(
|
87
|
+
opts[:header] || opts[:correlation_header] || CORRELATION_HEADER
|
88
|
+
)
|
89
|
+
|
90
|
+
@handler = opts.fetch(:handler, :clean)
|
91
|
+
@return = opts.fetch(:return, true)
|
92
|
+
@action_dispatch = opts.fetch(:action_dispatch, false)
|
93
|
+
|
94
|
+
yield self if block_given?
|
95
|
+
|
96
|
+
freeze
|
97
|
+
end
|
98
|
+
|
99
|
+
def to_hash
|
100
|
+
{
|
101
|
+
header: header,
|
102
|
+
handler: handler,
|
103
|
+
return: self.return,
|
104
|
+
action_dispatch: action_dispatch
|
105
|
+
}
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
def format_header_name(header)
|
111
|
+
[
|
112
|
+
header.to_s.tr("_", "-").freeze,
|
113
|
+
"HTTP_#{header.to_s.tr("-", "_").upcase}"
|
114
|
+
]
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "marlowe"
|
4
|
+
|
5
|
+
# Marlowe correlation ID middleware for Faraday. Including this into your
|
6
|
+
# request middleware stack will use the captured correlation ID.
|
7
|
+
class Marlowe::Faraday < Faraday::Middleware
|
8
|
+
def initialize(app, opts = {})
|
9
|
+
super(app)
|
10
|
+
@config = Marlowe::Config.override(opts)
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
env[:request_headers][@config.header] =
|
15
|
+
Marlowe.make_request_id(RequestStore[:correlation_id], @config)
|
16
|
+
@app.call(env)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
Faraday::Request.register_middleware marlowe: -> { Marlowe::Faraday }
|
data/lib/marlowe/formatter.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require "request_store"
|
4
4
|
|
5
|
+
module Marlowe
|
5
6
|
# Marlowe::Formatter is a subclass of +ActiveSupport::Logger::Formatter+
|
6
7
|
# that adds a correlation id string to a rails log.
|
7
8
|
class Formatter < ActiveSupport::Logger::Formatter
|
8
|
-
|
9
9
|
# Overrides the formatter return to add the correlation id.
|
10
|
-
def call(
|
10
|
+
def call(_severity, _timestamp, _progname, _msg)
|
11
11
|
"[#{RequestStore.store[:correlation_id]}] #{super}"
|
12
12
|
end
|
13
13
|
end
|
data/lib/marlowe/middleware.rb
CHANGED
@@ -1,36 +1,66 @@
|
|
1
|
-
|
2
|
-
require 'request_store'
|
3
|
-
require 'securerandom'
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
# request, and save that id in a request session variable.
|
9
|
-
|
10
|
-
# Name of the default header to look for and put the correlation id in.
|
11
|
-
CORRELATION_HEADER = 'Correlation-Id'.freeze
|
3
|
+
require "rack"
|
4
|
+
require "request_store"
|
5
|
+
require "securerandom"
|
12
6
|
|
7
|
+
module Marlowe
|
8
|
+
# Marlowe correlation id middleware. Including this into your middleware
|
9
|
+
# stack will capture or add a correlation id header on an incoming request,
|
10
|
+
# and save that id in a request session variable.
|
13
11
|
class Middleware
|
14
|
-
#
|
15
|
-
|
12
|
+
# The name of the default header to look for and put the correlation id in.
|
13
|
+
CORRELATION_HEADER = Marlowe::Config::CORRELATION_HEADER # :nodoc:
|
14
|
+
|
15
|
+
# Configure the Marlowe middleware to call +app+ with options +opts+.
|
16
|
+
#
|
17
|
+
# === Options
|
18
|
+
#
|
19
|
+
# <tt>:header</tt>:: The name of the header to inspect. Defaults to
|
20
|
+
# 'X-Request-Id'. Also available as
|
21
|
+
# <tt>:correlation_header</tt>.
|
22
|
+
# <tt>:handler</tt>:: The handler for request correlation IDs. Defaults to
|
23
|
+
# sanitizing provided request IDs or generating a UUID.
|
24
|
+
# If <tt>:simple</tt> is provided, provided request IDs
|
25
|
+
# will not be sanitized. A callable (expecting a single
|
26
|
+
# input of any possible existing request ID) may be
|
27
|
+
# provided to introduce more complex request ID
|
28
|
+
# handling.
|
29
|
+
# <tt>:return</tt>:: If +true+ (the default), the request correlation ID
|
30
|
+
# will be returned as part of the response headers.
|
31
|
+
# <tt>:action_dispatch</tt>:: If +true+, Marlowe will add code to behave
|
32
|
+
# like <tt>ActionDispatch::RequestId</tt>.
|
33
|
+
# Depends on <tt>ActionDispatch::Request</tt>.
|
34
|
+
def initialize(app, opts = nil)
|
16
35
|
@app = app
|
17
|
-
@
|
36
|
+
@config = Marlowe::Config.override(opts)
|
18
37
|
end
|
19
38
|
|
20
39
|
# Stores the incoming correlation id from the +env+ hash. If the correlation
|
21
40
|
# id has not been sent, a new UUID is generated and the +env+ is modified.
|
22
41
|
def call(env)
|
23
|
-
env[
|
24
|
-
RequestStore.store[:correlation_id] = env[
|
42
|
+
req_id = Marlowe.make_request_id(env[config.http_header], config)
|
43
|
+
RequestStore.store[:correlation_id] = env[config.http_header] = req_id
|
44
|
+
|
45
|
+
if config.action_dispatch
|
46
|
+
req = ActionDispatch::Request.new(env)
|
47
|
+
req.request_id = req_id
|
48
|
+
end
|
25
49
|
|
26
|
-
|
27
|
-
|
50
|
+
app.call(env).tap { |_status, headers, _body|
|
51
|
+
if config.return
|
52
|
+
headers[config.header] =
|
53
|
+
if config.action_dispatch
|
54
|
+
req.request_id
|
55
|
+
else
|
56
|
+
RequestStore.store[:correlation_id]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
}
|
28
60
|
end
|
29
61
|
|
30
62
|
private
|
31
63
|
|
32
|
-
|
33
|
-
("HTTP_" + header.gsub(/-/, '_').upcase).freeze
|
34
|
-
end
|
64
|
+
attr_reader :app, :config
|
35
65
|
end
|
36
66
|
end
|
data/lib/marlowe/rails.rb
CHANGED
@@ -1,11 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Marlowe
|
2
|
-
class Railtie < Rails::Railtie
|
3
|
-
initializer
|
4
|
-
|
4
|
+
class Railtie < Rails::Railtie # :nodoc:
|
5
|
+
initializer "marlowe.configure_rails_initialization" do
|
6
|
+
config = app.config
|
7
|
+
|
8
|
+
opts = {
|
9
|
+
header: config&.marlowe_header || config&.marlowe_correlation_header,
|
10
|
+
handler: config&.marlowe_request_id_handler,
|
11
|
+
return: config&.marlowe_return_request_id,
|
12
|
+
action_dispatch: config&.marlowe_replace_action_dispatch_request_id
|
13
|
+
}.compact
|
14
|
+
|
15
|
+
if opts[:action_dispatch]
|
16
|
+
app.middleware.insert_before ActionDispatch::RequestId, Marlowe::Middleware, opts
|
17
|
+
app.middleware.delete ActionDispatch::RequestId
|
18
|
+
else
|
19
|
+
app.middleware.insert_before Rails::Rack::Logger, Marlowe::Middleware, opts
|
20
|
+
end
|
5
21
|
end
|
6
22
|
|
7
|
-
|
8
|
-
def app
|
23
|
+
def app # :nodoc:
|
9
24
|
Rails.application
|
10
25
|
end
|
11
26
|
end
|
@@ -1,16 +1,15 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "request_store"
|
2
4
|
|
3
5
|
module Marlowe
|
4
6
|
# Marlowe::SimpleFormatter is a subclass of
|
5
7
|
# +ActiveSupport::Logger::SimpleFormatter+ that adds a correlation id
|
6
8
|
# string to a rails log.
|
7
9
|
class SimpleFormatter < ActiveSupport::Logger::SimpleFormatter
|
8
|
-
|
9
10
|
# Overrides the formatter return to add the correlation id.
|
10
11
|
def call(severity, timestamp, progname, msg)
|
11
12
|
"[#{RequestStore.store[:correlation_id]}] #{super}"
|
12
13
|
end
|
13
14
|
end
|
14
15
|
end
|
15
|
-
|
16
|
-
|
data/lib/marlowe.rb
CHANGED
@@ -1,10 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Marlowe, a correlation id injector.
|
2
4
|
module Marlowe
|
3
|
-
VERSION =
|
5
|
+
VERSION = "3.0" # :nodoc:
|
6
|
+
|
7
|
+
require "marlowe/config"
|
8
|
+
require "marlowe/middleware"
|
9
|
+
require "marlowe/rails" if defined? Rails::Railtie
|
10
|
+
|
11
|
+
autoload :Formatter, "marlowe/formatter"
|
12
|
+
autoload :SimpleFormatter, "marlowe/simple_formatter"
|
13
|
+
|
14
|
+
class << self
|
15
|
+
# Configure Marlowe
|
16
|
+
def configure(&block)
|
17
|
+
Marlowe::Config.configure(&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Make a Marlowe request ID
|
21
|
+
def make_request_id(request_id, config = Marlowe::Config.global)
|
22
|
+
if config.handler == :simple
|
23
|
+
simple(request_id)
|
24
|
+
elsif config.handler.is_a?(Proc)
|
25
|
+
simple(config.handler.call(request_id))
|
26
|
+
else
|
27
|
+
clean(request_id)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
4
32
|
|
5
|
-
|
6
|
-
|
33
|
+
def clean(request_id)
|
34
|
+
simple(request_id).gsub(/[^\w\-]/, "")[0, 255]
|
35
|
+
end
|
7
36
|
|
8
|
-
|
9
|
-
|
37
|
+
def simple(request_id)
|
38
|
+
if request_id && !request_id.empty? && request_id !~ /\A[[:space]]*\z/
|
39
|
+
request_id
|
40
|
+
else
|
41
|
+
SecureRandom.uuid
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
10
45
|
end
|
data/test/minitest_config.rb
CHANGED
@@ -1,22 +1,11 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
gem
|
3
|
+
gem "minitest"
|
4
4
|
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require 'minitest/bisect'
|
5
|
+
require "rack/test"
|
6
|
+
require "rack/mock"
|
7
|
+
require "minitest/autorun"
|
8
|
+
require "minitest/focus"
|
9
|
+
require "minitest/moar"
|
11
10
|
|
12
|
-
require
|
13
|
-
require 'marlowe'
|
14
|
-
|
15
|
-
class RackApp
|
16
|
-
def call(env)
|
17
|
-
end
|
18
|
-
|
19
|
-
def coordination_id
|
20
|
-
RequestStore[:correlation_id]
|
21
|
-
end
|
22
|
-
end
|
11
|
+
require "marlowe"
|
data/test/test_marlowe.rb
CHANGED
@@ -1,32 +1,103 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "minitest_config"
|
2
4
|
|
3
5
|
class TestMarlowe < Minitest::Test
|
6
|
+
include Rack::Test::Methods
|
7
|
+
|
8
|
+
attr_reader :marlowe_options
|
9
|
+
|
4
10
|
def setup
|
5
|
-
@
|
6
|
-
|
11
|
+
@marlowe_options = {}
|
12
|
+
Marlowe::Config.send(:clear_global!)
|
13
|
+
end
|
14
|
+
|
15
|
+
def app
|
16
|
+
options = marlowe_options
|
17
|
+
Rack::Builder.new do
|
18
|
+
use Marlowe::Middleware, options
|
19
|
+
|
20
|
+
run lambda { |_env|
|
21
|
+
[
|
22
|
+
200,
|
23
|
+
{"Content-Type" => "text/plain"},
|
24
|
+
[RequestStore[:correlation_id]]
|
25
|
+
]
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_default_config_no_header_value
|
31
|
+
get "/"
|
32
|
+
assert last_response.header.key?("X-Request-Id")
|
33
|
+
refute_empty last_response.header["X-Request-Id"]
|
34
|
+
assert_equal last_response.header["X-Request-Id"], last_response.body
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_default_config_with_header_value
|
38
|
+
get "/", {}, {"HTTP_X_REQUEST_ID" => "testvalue"}
|
39
|
+
assert last_response.header.key?("X-Request-Id")
|
40
|
+
refute_empty last_response.header["X-Request-Id"]
|
41
|
+
assert_equal last_response.header["X-Request-Id"], last_response.body
|
42
|
+
assert_equal "testvalue", last_response.header["X-Request-Id"]
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_header_config_no_header_value
|
46
|
+
marlowe_options[:header] = "Correlation-Id"
|
47
|
+
get "/"
|
48
|
+
assert last_response.header.key?("Correlation-Id")
|
49
|
+
refute_empty last_response.header["Correlation-Id"]
|
50
|
+
assert_equal last_response.header["Correlation-Id"], last_response.body
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_header_config_no_header_with_header_value
|
54
|
+
marlowe_options[:header] = "Correlation-Id"
|
55
|
+
get "/", {}, {"HTTP_CORRELATION_ID" => "testvalue"}
|
56
|
+
assert last_response.header.key?("Correlation-Id")
|
57
|
+
refute_empty last_response.header["Correlation-Id"]
|
58
|
+
assert_equal last_response.header["Correlation-Id"], last_response.body
|
59
|
+
assert_equal "testvalue", last_response.header["Correlation-Id"]
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_handler_config_default_handler
|
63
|
+
get "/", {}, {"HTTP_X_REQUEST_ID" => "test+value"}
|
64
|
+
assert last_response.header.key?("X-Request-Id")
|
65
|
+
refute_empty last_response.header["X-Request-Id"]
|
66
|
+
assert_equal last_response.header["X-Request-Id"], last_response.body
|
67
|
+
assert_equal "testvalue", last_response.header["X-Request-Id"]
|
7
68
|
end
|
8
69
|
|
9
|
-
def
|
10
|
-
|
11
|
-
|
70
|
+
def test_handler_config_with_simple_handler
|
71
|
+
marlowe_options[:handler] = :simple
|
72
|
+
get "/", {}, {"HTTP_X_REQUEST_ID" => "test+value"}
|
73
|
+
assert last_response.header.key?("X-Request-Id")
|
74
|
+
refute_empty last_response.header["X-Request-Id"]
|
75
|
+
assert_equal last_response.header["X-Request-Id"], last_response.body
|
76
|
+
assert_equal "test+value", last_response.header["X-Request-Id"]
|
12
77
|
end
|
13
78
|
|
14
|
-
def
|
15
|
-
|
16
|
-
|
17
|
-
|
79
|
+
def test_handler_config_with_proc_handler
|
80
|
+
marlowe_options[:handler] = ->(item) { item && item.reverse || SecureRandom.uuid }
|
81
|
+
get "/", {}, {"HTTP_X_REQUEST_ID" => "test+value"}
|
82
|
+
assert last_response.header.key?("X-Request-Id")
|
83
|
+
refute_empty last_response.header["X-Request-Id"]
|
84
|
+
assert_equal last_response.header["X-Request-Id"], last_response.body
|
85
|
+
assert_equal "eulav+tset", last_response.header["X-Request-Id"]
|
18
86
|
end
|
19
87
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
88
|
+
def test_handler_config_with_proc_handler_returning_nil
|
89
|
+
marlowe_options[:handler] = ->(_item) {}
|
90
|
+
get "/", {}, {"HTTP_X_REQUEST_ID" => "test+value"}
|
91
|
+
assert last_response.header.key?("X-Request-Id")
|
92
|
+
refute_empty last_response.header["X-Request-Id"]
|
93
|
+
assert_equal last_response.header["X-Request-Id"], last_response.body
|
94
|
+
assert_match(/\A[-\w]+\z/, last_response.header["X-Request-Id"])
|
24
95
|
end
|
25
96
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
assert_equal
|
97
|
+
def test_return_config_false
|
98
|
+
marlowe_options[:return] = false
|
99
|
+
get "/"
|
100
|
+
refute last_response.header.key?("X-Request-Id")
|
101
|
+
assert_equal RequestStore[:correlation_id], last_response.body
|
31
102
|
end
|
32
103
|
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "minitest_config"
|
4
|
+
|
5
|
+
class TestMarloweConfig < Minitest::Test
|
6
|
+
include Rack::Test::Methods
|
7
|
+
|
8
|
+
attr_reader :marlowe_options
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@marlowe_options = {}
|
12
|
+
Marlowe::Config.send(:clear_global!)
|
13
|
+
end
|
14
|
+
|
15
|
+
def app
|
16
|
+
Marlowe.configure do |config|
|
17
|
+
marlowe_options.each do |k, v|
|
18
|
+
config.send(:"#{k}=", v) if config.respond_to?(:"#{k}=")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
options = marlowe_options
|
23
|
+
Rack::Builder.new do
|
24
|
+
use Marlowe::Middleware, options
|
25
|
+
|
26
|
+
run lambda { |_env|
|
27
|
+
[
|
28
|
+
200,
|
29
|
+
{"Content-Type" => "text/plain"},
|
30
|
+
[RequestStore[:correlation_id]]
|
31
|
+
]
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_default_config_no_header_value
|
37
|
+
get "/"
|
38
|
+
assert last_response.header.key?("X-Request-Id")
|
39
|
+
refute_empty last_response.header["X-Request-Id"]
|
40
|
+
assert_equal last_response.header["X-Request-Id"], last_response.body
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_default_config_with_header_value
|
44
|
+
get "/", {}, {"HTTP_X_REQUEST_ID" => "testvalue"}
|
45
|
+
assert last_response.header.key?("X-Request-Id")
|
46
|
+
refute_empty last_response.header["X-Request-Id"]
|
47
|
+
assert_equal last_response.header["X-Request-Id"], last_response.body
|
48
|
+
assert_equal "testvalue", last_response.header["X-Request-Id"]
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_header_config_no_header_value
|
52
|
+
marlowe_options[:header] = "Correlation-Id"
|
53
|
+
get "/"
|
54
|
+
assert last_response.header.key?("Correlation-Id")
|
55
|
+
refute_empty last_response.header["Correlation-Id"]
|
56
|
+
assert_equal last_response.header["Correlation-Id"], last_response.body
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_header_config_no_header_with_header_value
|
60
|
+
marlowe_options[:header] = "Correlation-Id"
|
61
|
+
get "/", {}, {"HTTP_CORRELATION_ID" => "testvalue"}
|
62
|
+
assert last_response.header.key?("Correlation-Id")
|
63
|
+
refute_empty last_response.header["Correlation-Id"]
|
64
|
+
assert_equal last_response.header["Correlation-Id"], last_response.body
|
65
|
+
assert_equal "testvalue", last_response.header["Correlation-Id"]
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_handler_config_default_handler
|
69
|
+
get "/", {}, {"HTTP_X_REQUEST_ID" => "test+value"}
|
70
|
+
assert last_response.header.key?("X-Request-Id")
|
71
|
+
refute_empty last_response.header["X-Request-Id"]
|
72
|
+
assert_equal last_response.header["X-Request-Id"], last_response.body
|
73
|
+
assert_equal "testvalue", last_response.header["X-Request-Id"]
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_handler_config_with_simple_handler
|
77
|
+
marlowe_options[:handler] = :simple
|
78
|
+
get "/", {}, {"HTTP_X_REQUEST_ID" => "test+value"}
|
79
|
+
assert last_response.header.key?("X-Request-Id")
|
80
|
+
refute_empty last_response.header["X-Request-Id"]
|
81
|
+
assert_equal last_response.header["X-Request-Id"], last_response.body
|
82
|
+
assert_equal "test+value", last_response.header["X-Request-Id"]
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_handler_config_with_proc_handler
|
86
|
+
marlowe_options[:handler] = ->(item) { item && item.reverse || SecureRandom.uuid }
|
87
|
+
get "/", {}, {"HTTP_X_REQUEST_ID" => "test+value"}
|
88
|
+
assert last_response.header.key?("X-Request-Id")
|
89
|
+
refute_empty last_response.header["X-Request-Id"]
|
90
|
+
assert_equal last_response.header["X-Request-Id"], last_response.body
|
91
|
+
assert_equal "eulav+tset", last_response.header["X-Request-Id"]
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_handler_config_with_proc_handler_returning_nil
|
95
|
+
marlowe_options[:handler] = ->(_item) {}
|
96
|
+
get "/", {}, {"HTTP_X_REQUEST_ID" => "test+value"}
|
97
|
+
assert last_response.header.key?("X-Request-Id")
|
98
|
+
refute_empty last_response.header["X-Request-Id"]
|
99
|
+
assert_equal last_response.header["X-Request-Id"], last_response.body
|
100
|
+
assert_match(/\A[-\w]+\z/, last_response.header["X-Request-Id"])
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_return_config_false
|
104
|
+
marlowe_options[:return] = false
|
105
|
+
get "/"
|
106
|
+
refute last_response.header.key?("X-Request-Id")
|
107
|
+
assert_equal RequestStore[:correlation_id], last_response.body
|
108
|
+
end
|
109
|
+
end
|