puma--puma/test/test_rack_handler.rb

276 lines
6.9 KiB
Ruby
Raw Normal View History

require_relative "helper"
2011-10-04 21:23:51 +00:00
require "rack"
2016-02-03 20:06:10 +00:00
if Rack::RELEASE < '3'
2016-02-03 20:06:10 +00:00
require "rack/handler/puma"
2016-02-03 20:06:10 +00:00
class TestHandlerGetStrSym < Minitest::Test
def test_handler
handler = Rack::Handler.get(:puma)
assert_equal Rack::Handler::Puma, handler
handler = Rack::Handler.get('Puma')
assert_equal Rack::Handler::Puma, handler
end
end
class TestPathHandler < Minitest::Test
def app
Proc.new {|env| @input = env; [200, {}, ["hello world"]]}
2016-02-03 20:06:10 +00:00
end
def setup
@input = nil
2016-02-03 20:06:10 +00:00
end
def in_handler(app, options = {})
options[:Port] ||= 0
options[:Silent] = true
@launcher = nil
thread = Thread.new do
Rack::Handler::Puma.run(app, **options) do |s, p|
@launcher = s
end
end
# Wait for launcher to boot
Timeout.timeout(10) do
sleep 0.5 until @launcher
end
sleep 1.5 unless Puma::IS_MRI
2016-02-03 20:06:10 +00:00
yield @launcher
ensure
@launcher&.stop
thread&.join
2016-02-03 20:06:10 +00:00
end
Implement user_supplied_options behavior. When options are passed to the Puma rack handler it is unknown if the options were set via a framework as a default or via a user. Puma currently has 3 different sources of configuration, the user via command line, the config files, and defaults. Rails 5.1+ will record the values actually specified by the user versus the values specified by the frameworks. It passes these values to the Rack handler and now it's up to Puma to do something with that information. When only framework defaults are passed it will set ``` options[:user_supplied_options] = [] ``` When one or more options are specified by the user such as `:Port` then those keys will be in the array. In that example it will look like this ``` options[:user_supplied_options] = [:Port] ``` This change is 100% backwards compatible. If the framework is older and does not pass this information then the `user_supplied_options` will not be set, in that case we assume all values are user supplied. Internally we accomplish this separation by replacing `LeveledOptions` which was a generic way of specifying options with different priorities with a more explicit `UserFileDefaultOptions` this assumes only 3 levels of options and it will use them in the order supplied (user config wins over file based config wins over defaults). Now instead of using 1 dsl to set all values, we use 3. A user dsl, a file dsl and a Configuration.new` will return all 3 DSLs to the block. It's up to the person using the block to use the correct dsl corresponding to the source of data they are getting.
2017-03-03 22:04:56 +00:00
def test_handler_boots
host = '127.0.0.1'
port = UniquePort.call
opts = { Host: host, Port: port }
in_handler(app, opts) do |launcher|
hit(["http://#{host}:#{port}/test"])
assert_equal("/test", @input["PATH_INFO"])
end
end
Implement user_supplied_options behavior. When options are passed to the Puma rack handler it is unknown if the options were set via a framework as a default or via a user. Puma currently has 3 different sources of configuration, the user via command line, the config files, and defaults. Rails 5.1+ will record the values actually specified by the user versus the values specified by the frameworks. It passes these values to the Rack handler and now it's up to Puma to do something with that information. When only framework defaults are passed it will set ``` options[:user_supplied_options] = [] ``` When one or more options are specified by the user such as `:Port` then those keys will be in the array. In that example it will look like this ``` options[:user_supplied_options] = [:Port] ``` This change is 100% backwards compatible. If the framework is older and does not pass this information then the `user_supplied_options` will not be set, in that case we assume all values are user supplied. Internally we accomplish this separation by replacing `LeveledOptions` which was a generic way of specifying options with different priorities with a more explicit `UserFileDefaultOptions` this assumes only 3 levels of options and it will use them in the order supplied (user config wins over file based config wins over defaults). Now instead of using 1 dsl to set all values, we use 3. A user dsl, a file dsl and a Configuration.new` will return all 3 DSLs to the block. It's up to the person using the block to use the correct dsl corresponding to the source of data they are getting.
2017-03-03 22:04:56 +00:00
end
class TestUserSuppliedOptionsPortIsSet < Minitest::Test
def setup
@options = {}
@options[:user_supplied_options] = [:Port]
end
def test_port_wins_over_config
user_port = 5001
file_port = 6001
2016-02-03 20:06:10 +00:00
Dir.mktmpdir do |d|
Dir.chdir(d) do
FileUtils.mkdir("config")
File.open("config/puma.rb", "w") { |f| f << "port #{file_port}" }
@options[:Port] = user_port
conf = Rack::Handler::Puma.config(->{}, @options)
conf.load
assert_equal ["tcp://0.0.0.0:#{user_port}"], conf.options[:binds]
end
Implement user_supplied_options behavior. When options are passed to the Puma rack handler it is unknown if the options were set via a framework as a default or via a user. Puma currently has 3 different sources of configuration, the user via command line, the config files, and defaults. Rails 5.1+ will record the values actually specified by the user versus the values specified by the frameworks. It passes these values to the Rack handler and now it's up to Puma to do something with that information. When only framework defaults are passed it will set ``` options[:user_supplied_options] = [] ``` When one or more options are specified by the user such as `:Port` then those keys will be in the array. In that example it will look like this ``` options[:user_supplied_options] = [:Port] ``` This change is 100% backwards compatible. If the framework is older and does not pass this information then the `user_supplied_options` will not be set, in that case we assume all values are user supplied. Internally we accomplish this separation by replacing `LeveledOptions` which was a generic way of specifying options with different priorities with a more explicit `UserFileDefaultOptions` this assumes only 3 levels of options and it will use them in the order supplied (user config wins over file based config wins over defaults). Now instead of using 1 dsl to set all values, we use 3. A user dsl, a file dsl and a Configuration.new` will return all 3 DSLs to the block. It's up to the person using the block to use the correct dsl corresponding to the source of data they are getting.
2017-03-03 22:04:56 +00:00
end
end
end
class TestUserSuppliedOptionsHostIsSet < Minitest::Test
def setup
@options = {}
@options[:user_supplied_options] = [:Host]
end
def test_host_uses_supplied_port_default
user_port = rand(1000..9999)
user_host = "123.456.789"
@options[:Host] = user_host
@options[:Port] = user_port
conf = Rack::Handler::Puma.config(->{}, @options)
conf.load
assert_equal ["tcp://#{user_host}:#{user_port}"], conf.options[:binds]
end
def test_ipv6_host_supplied_port_default
@options[:Host] = "::1"
conf = Rack::Handler::Puma.config(->{}, @options)
conf.load
assert_equal ["tcp://[::1]:9292"], conf.options[:binds]
end
end
class TestUserSuppliedOptionsIsEmpty < Minitest::Test
def setup
@options = {}
@options[:user_supplied_options] = []
end
def test_config_file_wins_over_port
user_port = 5001
file_port = 6001
Implement user_supplied_options behavior. When options are passed to the Puma rack handler it is unknown if the options were set via a framework as a default or via a user. Puma currently has 3 different sources of configuration, the user via command line, the config files, and defaults. Rails 5.1+ will record the values actually specified by the user versus the values specified by the frameworks. It passes these values to the Rack handler and now it's up to Puma to do something with that information. When only framework defaults are passed it will set ``` options[:user_supplied_options] = [] ``` When one or more options are specified by the user such as `:Port` then those keys will be in the array. In that example it will look like this ``` options[:user_supplied_options] = [:Port] ``` This change is 100% backwards compatible. If the framework is older and does not pass this information then the `user_supplied_options` will not be set, in that case we assume all values are user supplied. Internally we accomplish this separation by replacing `LeveledOptions` which was a generic way of specifying options with different priorities with a more explicit `UserFileDefaultOptions` this assumes only 3 levels of options and it will use them in the order supplied (user config wins over file based config wins over defaults). Now instead of using 1 dsl to set all values, we use 3. A user dsl, a file dsl and a Configuration.new` will return all 3 DSLs to the block. It's up to the person using the block to use the correct dsl corresponding to the source of data they are getting.
2017-03-03 22:04:56 +00:00
Dir.mktmpdir do |d|
Dir.chdir(d) do
FileUtils.mkdir("config")
File.open("config/puma.rb", "w") { |f| f << "port #{file_port}" }
Implement user_supplied_options behavior. When options are passed to the Puma rack handler it is unknown if the options were set via a framework as a default or via a user. Puma currently has 3 different sources of configuration, the user via command line, the config files, and defaults. Rails 5.1+ will record the values actually specified by the user versus the values specified by the frameworks. It passes these values to the Rack handler and now it's up to Puma to do something with that information. When only framework defaults are passed it will set ``` options[:user_supplied_options] = [] ``` When one or more options are specified by the user such as `:Port` then those keys will be in the array. In that example it will look like this ``` options[:user_supplied_options] = [:Port] ``` This change is 100% backwards compatible. If the framework is older and does not pass this information then the `user_supplied_options` will not be set, in that case we assume all values are user supplied. Internally we accomplish this separation by replacing `LeveledOptions` which was a generic way of specifying options with different priorities with a more explicit `UserFileDefaultOptions` this assumes only 3 levels of options and it will use them in the order supplied (user config wins over file based config wins over defaults). Now instead of using 1 dsl to set all values, we use 3. A user dsl, a file dsl and a Configuration.new` will return all 3 DSLs to the block. It's up to the person using the block to use the correct dsl corresponding to the source of data they are getting.
2017-03-03 22:04:56 +00:00
@options[:Port] = user_port
conf = Rack::Handler::Puma.config(->{}, @options)
conf.load
Implement user_supplied_options behavior. When options are passed to the Puma rack handler it is unknown if the options were set via a framework as a default or via a user. Puma currently has 3 different sources of configuration, the user via command line, the config files, and defaults. Rails 5.1+ will record the values actually specified by the user versus the values specified by the frameworks. It passes these values to the Rack handler and now it's up to Puma to do something with that information. When only framework defaults are passed it will set ``` options[:user_supplied_options] = [] ``` When one or more options are specified by the user such as `:Port` then those keys will be in the array. In that example it will look like this ``` options[:user_supplied_options] = [:Port] ``` This change is 100% backwards compatible. If the framework is older and does not pass this information then the `user_supplied_options` will not be set, in that case we assume all values are user supplied. Internally we accomplish this separation by replacing `LeveledOptions` which was a generic way of specifying options with different priorities with a more explicit `UserFileDefaultOptions` this assumes only 3 levels of options and it will use them in the order supplied (user config wins over file based config wins over defaults). Now instead of using 1 dsl to set all values, we use 3. A user dsl, a file dsl and a Configuration.new` will return all 3 DSLs to the block. It's up to the person using the block to use the correct dsl corresponding to the source of data they are getting.
2017-03-03 22:04:56 +00:00
assert_equal ["tcp://0.0.0.0:#{file_port}"], conf.options[:binds]
end
Implement user_supplied_options behavior. When options are passed to the Puma rack handler it is unknown if the options were set via a framework as a default or via a user. Puma currently has 3 different sources of configuration, the user via command line, the config files, and defaults. Rails 5.1+ will record the values actually specified by the user versus the values specified by the frameworks. It passes these values to the Rack handler and now it's up to Puma to do something with that information. When only framework defaults are passed it will set ``` options[:user_supplied_options] = [] ``` When one or more options are specified by the user such as `:Port` then those keys will be in the array. In that example it will look like this ``` options[:user_supplied_options] = [:Port] ``` This change is 100% backwards compatible. If the framework is older and does not pass this information then the `user_supplied_options` will not be set, in that case we assume all values are user supplied. Internally we accomplish this separation by replacing `LeveledOptions` which was a generic way of specifying options with different priorities with a more explicit `UserFileDefaultOptions` this assumes only 3 levels of options and it will use them in the order supplied (user config wins over file based config wins over defaults). Now instead of using 1 dsl to set all values, we use 3. A user dsl, a file dsl and a Configuration.new` will return all 3 DSLs to the block. It's up to the person using the block to use the correct dsl corresponding to the source of data they are getting.
2017-03-03 22:04:56 +00:00
end
end
Rack handler should use provided default host This issue is somewhat tricky. When Rails is booted via `rails server` there are two types of configuration options passed, ones specified directly by a user like `rails s -p 3001` will always "win". For any other config that is not explicitly passed in, puma will consider it a "default". For example when you run `rails s` (without -p) then the default port will be 3000. There is one other way to configure puma though, and that is via a config file: ``` # config/puma.rb port 3002 ``` This is the order of precedence for configuration 1) Anything the user explicitly passes to `rails s` 2) Config specified in `config/puma.rb` file 3) Default values passed in via `rails s` 4) Defaults values stored in puma This fallback mechanism works well except in the case of calling `port` in a `config/puma.rb` file. To understand look at the [old method definition](https://github.com/puma/puma/blob/2668597ec1dd9546d83db9f2ec5ad092add483e6/lib/puma/dsl.rb#L140-L145): ``` def port(port, host=nil) host ||= Configuration::DefaultTCPHost bind "tcp://#{host}:#{port}" end ``` When the `port` method gets called, even if the user did not specify a `host` the `Configuration::DefaultTCPHost` will be used, which is a problem for local development because it defaults to `0.0.0.0`. [SO about 0.0.0.0 versus localhost](https://stackoverflow.com/questions/20778771/what-is-the-difference-between-0-0-0-0-127-0-0-1-and-localhost). In this case, while a user did directly specify a port, they did not specify a host, so you would expect the `rails s` defaults passed in to take affect. To make Puma respect that the host coming from `rails s` has more precedence than it's own default host, we must introduce the ability to set and retrieve a default_host value. This is then used in the rack handler so when `rails s` passes in `:Host => "localhost"` then it is used instead of reverting to `0.0.0.0`. The issue with #1699 is the test was wrong, it would have failed if a config file was present with a `port` invocation.
2019-01-04 19:15:31 +00:00
def test_default_host_when_using_config_file
user_port = 5001
file_port = 6001
Rack handler should use provided default host This issue is somewhat tricky. When Rails is booted via `rails server` there are two types of configuration options passed, ones specified directly by a user like `rails s -p 3001` will always "win". For any other config that is not explicitly passed in, puma will consider it a "default". For example when you run `rails s` (without -p) then the default port will be 3000. There is one other way to configure puma though, and that is via a config file: ``` # config/puma.rb port 3002 ``` This is the order of precedence for configuration 1) Anything the user explicitly passes to `rails s` 2) Config specified in `config/puma.rb` file 3) Default values passed in via `rails s` 4) Defaults values stored in puma This fallback mechanism works well except in the case of calling `port` in a `config/puma.rb` file. To understand look at the [old method definition](https://github.com/puma/puma/blob/2668597ec1dd9546d83db9f2ec5ad092add483e6/lib/puma/dsl.rb#L140-L145): ``` def port(port, host=nil) host ||= Configuration::DefaultTCPHost bind "tcp://#{host}:#{port}" end ``` When the `port` method gets called, even if the user did not specify a `host` the `Configuration::DefaultTCPHost` will be used, which is a problem for local development because it defaults to `0.0.0.0`. [SO about 0.0.0.0 versus localhost](https://stackoverflow.com/questions/20778771/what-is-the-difference-between-0-0-0-0-127-0-0-1-and-localhost). In this case, while a user did directly specify a port, they did not specify a host, so you would expect the `rails s` defaults passed in to take affect. To make Puma respect that the host coming from `rails s` has more precedence than it's own default host, we must introduce the ability to set and retrieve a default_host value. This is then used in the rack handler so when `rails s` passes in `:Host => "localhost"` then it is used instead of reverting to `0.0.0.0`. The issue with #1699 is the test was wrong, it would have failed if a config file was present with a `port` invocation.
2019-01-04 19:15:31 +00:00
Dir.mktmpdir do |d|
Dir.chdir(d) do
FileUtils.mkdir("config")
File.open("config/puma.rb", "w") { |f| f << "port #{file_port}" }
Rack handler should use provided default host This issue is somewhat tricky. When Rails is booted via `rails server` there are two types of configuration options passed, ones specified directly by a user like `rails s -p 3001` will always "win". For any other config that is not explicitly passed in, puma will consider it a "default". For example when you run `rails s` (without -p) then the default port will be 3000. There is one other way to configure puma though, and that is via a config file: ``` # config/puma.rb port 3002 ``` This is the order of precedence for configuration 1) Anything the user explicitly passes to `rails s` 2) Config specified in `config/puma.rb` file 3) Default values passed in via `rails s` 4) Defaults values stored in puma This fallback mechanism works well except in the case of calling `port` in a `config/puma.rb` file. To understand look at the [old method definition](https://github.com/puma/puma/blob/2668597ec1dd9546d83db9f2ec5ad092add483e6/lib/puma/dsl.rb#L140-L145): ``` def port(port, host=nil) host ||= Configuration::DefaultTCPHost bind "tcp://#{host}:#{port}" end ``` When the `port` method gets called, even if the user did not specify a `host` the `Configuration::DefaultTCPHost` will be used, which is a problem for local development because it defaults to `0.0.0.0`. [SO about 0.0.0.0 versus localhost](https://stackoverflow.com/questions/20778771/what-is-the-difference-between-0-0-0-0-127-0-0-1-and-localhost). In this case, while a user did directly specify a port, they did not specify a host, so you would expect the `rails s` defaults passed in to take affect. To make Puma respect that the host coming from `rails s` has more precedence than it's own default host, we must introduce the ability to set and retrieve a default_host value. This is then used in the rack handler so when `rails s` passes in `:Host => "localhost"` then it is used instead of reverting to `0.0.0.0`. The issue with #1699 is the test was wrong, it would have failed if a config file was present with a `port` invocation.
2019-01-04 19:15:31 +00:00
@options[:Host] = "localhost"
@options[:Port] = user_port
conf = Rack::Handler::Puma.config(->{}, @options)
conf.load
Rack handler should use provided default host This issue is somewhat tricky. When Rails is booted via `rails server` there are two types of configuration options passed, ones specified directly by a user like `rails s -p 3001` will always "win". For any other config that is not explicitly passed in, puma will consider it a "default". For example when you run `rails s` (without -p) then the default port will be 3000. There is one other way to configure puma though, and that is via a config file: ``` # config/puma.rb port 3002 ``` This is the order of precedence for configuration 1) Anything the user explicitly passes to `rails s` 2) Config specified in `config/puma.rb` file 3) Default values passed in via `rails s` 4) Defaults values stored in puma This fallback mechanism works well except in the case of calling `port` in a `config/puma.rb` file. To understand look at the [old method definition](https://github.com/puma/puma/blob/2668597ec1dd9546d83db9f2ec5ad092add483e6/lib/puma/dsl.rb#L140-L145): ``` def port(port, host=nil) host ||= Configuration::DefaultTCPHost bind "tcp://#{host}:#{port}" end ``` When the `port` method gets called, even if the user did not specify a `host` the `Configuration::DefaultTCPHost` will be used, which is a problem for local development because it defaults to `0.0.0.0`. [SO about 0.0.0.0 versus localhost](https://stackoverflow.com/questions/20778771/what-is-the-difference-between-0-0-0-0-127-0-0-1-and-localhost). In this case, while a user did directly specify a port, they did not specify a host, so you would expect the `rails s` defaults passed in to take affect. To make Puma respect that the host coming from `rails s` has more precedence than it's own default host, we must introduce the ability to set and retrieve a default_host value. This is then used in the rack handler so when `rails s` passes in `:Host => "localhost"` then it is used instead of reverting to `0.0.0.0`. The issue with #1699 is the test was wrong, it would have failed if a config file was present with a `port` invocation.
2019-01-04 19:15:31 +00:00
assert_equal ["tcp://localhost:#{file_port}"], conf.options[:binds]
end
Rack handler should use provided default host This issue is somewhat tricky. When Rails is booted via `rails server` there are two types of configuration options passed, ones specified directly by a user like `rails s -p 3001` will always "win". For any other config that is not explicitly passed in, puma will consider it a "default". For example when you run `rails s` (without -p) then the default port will be 3000. There is one other way to configure puma though, and that is via a config file: ``` # config/puma.rb port 3002 ``` This is the order of precedence for configuration 1) Anything the user explicitly passes to `rails s` 2) Config specified in `config/puma.rb` file 3) Default values passed in via `rails s` 4) Defaults values stored in puma This fallback mechanism works well except in the case of calling `port` in a `config/puma.rb` file. To understand look at the [old method definition](https://github.com/puma/puma/blob/2668597ec1dd9546d83db9f2ec5ad092add483e6/lib/puma/dsl.rb#L140-L145): ``` def port(port, host=nil) host ||= Configuration::DefaultTCPHost bind "tcp://#{host}:#{port}" end ``` When the `port` method gets called, even if the user did not specify a `host` the `Configuration::DefaultTCPHost` will be used, which is a problem for local development because it defaults to `0.0.0.0`. [SO about 0.0.0.0 versus localhost](https://stackoverflow.com/questions/20778771/what-is-the-difference-between-0-0-0-0-127-0-0-1-and-localhost). In this case, while a user did directly specify a port, they did not specify a host, so you would expect the `rails s` defaults passed in to take affect. To make Puma respect that the host coming from `rails s` has more precedence than it's own default host, we must introduce the ability to set and retrieve a default_host value. This is then used in the rack handler so when `rails s` passes in `:Host => "localhost"` then it is used instead of reverting to `0.0.0.0`. The issue with #1699 is the test was wrong, it would have failed if a config file was present with a `port` invocation.
2019-01-04 19:15:31 +00:00
end
end
def test_default_host_when_using_config_file_with_explicit_host
user_port = 5001
file_port = 6001
Rack handler should use provided default host This issue is somewhat tricky. When Rails is booted via `rails server` there are two types of configuration options passed, ones specified directly by a user like `rails s -p 3001` will always "win". For any other config that is not explicitly passed in, puma will consider it a "default". For example when you run `rails s` (without -p) then the default port will be 3000. There is one other way to configure puma though, and that is via a config file: ``` # config/puma.rb port 3002 ``` This is the order of precedence for configuration 1) Anything the user explicitly passes to `rails s` 2) Config specified in `config/puma.rb` file 3) Default values passed in via `rails s` 4) Defaults values stored in puma This fallback mechanism works well except in the case of calling `port` in a `config/puma.rb` file. To understand look at the [old method definition](https://github.com/puma/puma/blob/2668597ec1dd9546d83db9f2ec5ad092add483e6/lib/puma/dsl.rb#L140-L145): ``` def port(port, host=nil) host ||= Configuration::DefaultTCPHost bind "tcp://#{host}:#{port}" end ``` When the `port` method gets called, even if the user did not specify a `host` the `Configuration::DefaultTCPHost` will be used, which is a problem for local development because it defaults to `0.0.0.0`. [SO about 0.0.0.0 versus localhost](https://stackoverflow.com/questions/20778771/what-is-the-difference-between-0-0-0-0-127-0-0-1-and-localhost). In this case, while a user did directly specify a port, they did not specify a host, so you would expect the `rails s` defaults passed in to take affect. To make Puma respect that the host coming from `rails s` has more precedence than it's own default host, we must introduce the ability to set and retrieve a default_host value. This is then used in the rack handler so when `rails s` passes in `:Host => "localhost"` then it is used instead of reverting to `0.0.0.0`. The issue with #1699 is the test was wrong, it would have failed if a config file was present with a `port` invocation.
2019-01-04 19:15:31 +00:00
Dir.mktmpdir do |d|
Dir.chdir(d) do
FileUtils.mkdir("config")
File.open("config/puma.rb", "w") { |f| f << "port #{file_port}, '1.2.3.4'" }
Rack handler should use provided default host This issue is somewhat tricky. When Rails is booted via `rails server` there are two types of configuration options passed, ones specified directly by a user like `rails s -p 3001` will always "win". For any other config that is not explicitly passed in, puma will consider it a "default". For example when you run `rails s` (without -p) then the default port will be 3000. There is one other way to configure puma though, and that is via a config file: ``` # config/puma.rb port 3002 ``` This is the order of precedence for configuration 1) Anything the user explicitly passes to `rails s` 2) Config specified in `config/puma.rb` file 3) Default values passed in via `rails s` 4) Defaults values stored in puma This fallback mechanism works well except in the case of calling `port` in a `config/puma.rb` file. To understand look at the [old method definition](https://github.com/puma/puma/blob/2668597ec1dd9546d83db9f2ec5ad092add483e6/lib/puma/dsl.rb#L140-L145): ``` def port(port, host=nil) host ||= Configuration::DefaultTCPHost bind "tcp://#{host}:#{port}" end ``` When the `port` method gets called, even if the user did not specify a `host` the `Configuration::DefaultTCPHost` will be used, which is a problem for local development because it defaults to `0.0.0.0`. [SO about 0.0.0.0 versus localhost](https://stackoverflow.com/questions/20778771/what-is-the-difference-between-0-0-0-0-127-0-0-1-and-localhost). In this case, while a user did directly specify a port, they did not specify a host, so you would expect the `rails s` defaults passed in to take affect. To make Puma respect that the host coming from `rails s` has more precedence than it's own default host, we must introduce the ability to set and retrieve a default_host value. This is then used in the rack handler so when `rails s` passes in `:Host => "localhost"` then it is used instead of reverting to `0.0.0.0`. The issue with #1699 is the test was wrong, it would have failed if a config file was present with a `port` invocation.
2019-01-04 19:15:31 +00:00
@options[:Host] = "localhost"
@options[:Port] = user_port
conf = Rack::Handler::Puma.config(->{}, @options)
conf.load
Rack handler should use provided default host This issue is somewhat tricky. When Rails is booted via `rails server` there are two types of configuration options passed, ones specified directly by a user like `rails s -p 3001` will always "win". For any other config that is not explicitly passed in, puma will consider it a "default". For example when you run `rails s` (without -p) then the default port will be 3000. There is one other way to configure puma though, and that is via a config file: ``` # config/puma.rb port 3002 ``` This is the order of precedence for configuration 1) Anything the user explicitly passes to `rails s` 2) Config specified in `config/puma.rb` file 3) Default values passed in via `rails s` 4) Defaults values stored in puma This fallback mechanism works well except in the case of calling `port` in a `config/puma.rb` file. To understand look at the [old method definition](https://github.com/puma/puma/blob/2668597ec1dd9546d83db9f2ec5ad092add483e6/lib/puma/dsl.rb#L140-L145): ``` def port(port, host=nil) host ||= Configuration::DefaultTCPHost bind "tcp://#{host}:#{port}" end ``` When the `port` method gets called, even if the user did not specify a `host` the `Configuration::DefaultTCPHost` will be used, which is a problem for local development because it defaults to `0.0.0.0`. [SO about 0.0.0.0 versus localhost](https://stackoverflow.com/questions/20778771/what-is-the-difference-between-0-0-0-0-127-0-0-1-and-localhost). In this case, while a user did directly specify a port, they did not specify a host, so you would expect the `rails s` defaults passed in to take affect. To make Puma respect that the host coming from `rails s` has more precedence than it's own default host, we must introduce the ability to set and retrieve a default_host value. This is then used in the rack handler so when `rails s` passes in `:Host => "localhost"` then it is used instead of reverting to `0.0.0.0`. The issue with #1699 is the test was wrong, it would have failed if a config file was present with a `port` invocation.
2019-01-04 19:15:31 +00:00
assert_equal ["tcp://1.2.3.4:#{file_port}"], conf.options[:binds]
end
Rack handler should use provided default host This issue is somewhat tricky. When Rails is booted via `rails server` there are two types of configuration options passed, ones specified directly by a user like `rails s -p 3001` will always "win". For any other config that is not explicitly passed in, puma will consider it a "default". For example when you run `rails s` (without -p) then the default port will be 3000. There is one other way to configure puma though, and that is via a config file: ``` # config/puma.rb port 3002 ``` This is the order of precedence for configuration 1) Anything the user explicitly passes to `rails s` 2) Config specified in `config/puma.rb` file 3) Default values passed in via `rails s` 4) Defaults values stored in puma This fallback mechanism works well except in the case of calling `port` in a `config/puma.rb` file. To understand look at the [old method definition](https://github.com/puma/puma/blob/2668597ec1dd9546d83db9f2ec5ad092add483e6/lib/puma/dsl.rb#L140-L145): ``` def port(port, host=nil) host ||= Configuration::DefaultTCPHost bind "tcp://#{host}:#{port}" end ``` When the `port` method gets called, even if the user did not specify a `host` the `Configuration::DefaultTCPHost` will be used, which is a problem for local development because it defaults to `0.0.0.0`. [SO about 0.0.0.0 versus localhost](https://stackoverflow.com/questions/20778771/what-is-the-difference-between-0-0-0-0-127-0-0-1-and-localhost). In this case, while a user did directly specify a port, they did not specify a host, so you would expect the `rails s` defaults passed in to take affect. To make Puma respect that the host coming from `rails s` has more precedence than it's own default host, we must introduce the ability to set and retrieve a default_host value. This is then used in the rack handler so when `rails s` passes in `:Host => "localhost"` then it is used instead of reverting to `0.0.0.0`. The issue with #1699 is the test was wrong, it would have failed if a config file was present with a `port` invocation.
2019-01-04 19:15:31 +00:00
end
end
end
Implement user_supplied_options behavior. When options are passed to the Puma rack handler it is unknown if the options were set via a framework as a default or via a user. Puma currently has 3 different sources of configuration, the user via command line, the config files, and defaults. Rails 5.1+ will record the values actually specified by the user versus the values specified by the frameworks. It passes these values to the Rack handler and now it's up to Puma to do something with that information. When only framework defaults are passed it will set ``` options[:user_supplied_options] = [] ``` When one or more options are specified by the user such as `:Port` then those keys will be in the array. In that example it will look like this ``` options[:user_supplied_options] = [:Port] ``` This change is 100% backwards compatible. If the framework is older and does not pass this information then the `user_supplied_options` will not be set, in that case we assume all values are user supplied. Internally we accomplish this separation by replacing `LeveledOptions` which was a generic way of specifying options with different priorities with a more explicit `UserFileDefaultOptions` this assumes only 3 levels of options and it will use them in the order supplied (user config wins over file based config wins over defaults). Now instead of using 1 dsl to set all values, we use 3. A user dsl, a file dsl and a Configuration.new` will return all 3 DSLs to the block. It's up to the person using the block to use the correct dsl corresponding to the source of data they are getting.
2017-03-03 22:04:56 +00:00
class TestUserSuppliedOptionsIsNotPresent < Minitest::Test
def setup
@options = {}
end
Implement user_supplied_options behavior. When options are passed to the Puma rack handler it is unknown if the options were set via a framework as a default or via a user. Puma currently has 3 different sources of configuration, the user via command line, the config files, and defaults. Rails 5.1+ will record the values actually specified by the user versus the values specified by the frameworks. It passes these values to the Rack handler and now it's up to Puma to do something with that information. When only framework defaults are passed it will set ``` options[:user_supplied_options] = [] ``` When one or more options are specified by the user such as `:Port` then those keys will be in the array. In that example it will look like this ``` options[:user_supplied_options] = [:Port] ``` This change is 100% backwards compatible. If the framework is older and does not pass this information then the `user_supplied_options` will not be set, in that case we assume all values are user supplied. Internally we accomplish this separation by replacing `LeveledOptions` which was a generic way of specifying options with different priorities with a more explicit `UserFileDefaultOptions` this assumes only 3 levels of options and it will use them in the order supplied (user config wins over file based config wins over defaults). Now instead of using 1 dsl to set all values, we use 3. A user dsl, a file dsl and a Configuration.new` will return all 3 DSLs to the block. It's up to the person using the block to use the correct dsl corresponding to the source of data they are getting.
2017-03-03 22:04:56 +00:00
def test_default_port_when_no_config_file
conf = Rack::Handler::Puma.config(->{}, @options)
conf.load
Implement user_supplied_options behavior. When options are passed to the Puma rack handler it is unknown if the options were set via a framework as a default or via a user. Puma currently has 3 different sources of configuration, the user via command line, the config files, and defaults. Rails 5.1+ will record the values actually specified by the user versus the values specified by the frameworks. It passes these values to the Rack handler and now it's up to Puma to do something with that information. When only framework defaults are passed it will set ``` options[:user_supplied_options] = [] ``` When one or more options are specified by the user such as `:Port` then those keys will be in the array. In that example it will look like this ``` options[:user_supplied_options] = [:Port] ``` This change is 100% backwards compatible. If the framework is older and does not pass this information then the `user_supplied_options` will not be set, in that case we assume all values are user supplied. Internally we accomplish this separation by replacing `LeveledOptions` which was a generic way of specifying options with different priorities with a more explicit `UserFileDefaultOptions` this assumes only 3 levels of options and it will use them in the order supplied (user config wins over file based config wins over defaults). Now instead of using 1 dsl to set all values, we use 3. A user dsl, a file dsl and a Configuration.new` will return all 3 DSLs to the block. It's up to the person using the block to use the correct dsl corresponding to the source of data they are getting.
2017-03-03 22:04:56 +00:00
assert_equal ["tcp://0.0.0.0:9292"], conf.options[:binds]
end
Implement user_supplied_options behavior. When options are passed to the Puma rack handler it is unknown if the options were set via a framework as a default or via a user. Puma currently has 3 different sources of configuration, the user via command line, the config files, and defaults. Rails 5.1+ will record the values actually specified by the user versus the values specified by the frameworks. It passes these values to the Rack handler and now it's up to Puma to do something with that information. When only framework defaults are passed it will set ``` options[:user_supplied_options] = [] ``` When one or more options are specified by the user such as `:Port` then those keys will be in the array. In that example it will look like this ``` options[:user_supplied_options] = [:Port] ``` This change is 100% backwards compatible. If the framework is older and does not pass this information then the `user_supplied_options` will not be set, in that case we assume all values are user supplied. Internally we accomplish this separation by replacing `LeveledOptions` which was a generic way of specifying options with different priorities with a more explicit `UserFileDefaultOptions` this assumes only 3 levels of options and it will use them in the order supplied (user config wins over file based config wins over defaults). Now instead of using 1 dsl to set all values, we use 3. A user dsl, a file dsl and a Configuration.new` will return all 3 DSLs to the block. It's up to the person using the block to use the correct dsl corresponding to the source of data they are getting.
2017-03-03 22:04:56 +00:00
def test_config_wins_over_default
file_port = 6001
Dir.mktmpdir do |d|
Dir.chdir(d) do
FileUtils.mkdir("config")
File.open("config/puma.rb", "w") { |f| f << "port #{file_port}" }
conf = Rack::Handler::Puma.config(->{}, @options)
conf.load
assert_equal ["tcp://0.0.0.0:#{file_port}"], conf.options[:binds]
end
end
end
Implement user_supplied_options behavior. When options are passed to the Puma rack handler it is unknown if the options were set via a framework as a default or via a user. Puma currently has 3 different sources of configuration, the user via command line, the config files, and defaults. Rails 5.1+ will record the values actually specified by the user versus the values specified by the frameworks. It passes these values to the Rack handler and now it's up to Puma to do something with that information. When only framework defaults are passed it will set ``` options[:user_supplied_options] = [] ``` When one or more options are specified by the user such as `:Port` then those keys will be in the array. In that example it will look like this ``` options[:user_supplied_options] = [:Port] ``` This change is 100% backwards compatible. If the framework is older and does not pass this information then the `user_supplied_options` will not be set, in that case we assume all values are user supplied. Internally we accomplish this separation by replacing `LeveledOptions` which was a generic way of specifying options with different priorities with a more explicit `UserFileDefaultOptions` this assumes only 3 levels of options and it will use them in the order supplied (user config wins over file based config wins over defaults). Now instead of using 1 dsl to set all values, we use 3. A user dsl, a file dsl and a Configuration.new` will return all 3 DSLs to the block. It's up to the person using the block to use the correct dsl corresponding to the source of data they are getting.
2017-03-03 22:04:56 +00:00
def test_user_port_wins_over_default_when_user_supplied_is_blank
user_port = 5001
@options[:user_supplied_options] = []
@options[:Port] = user_port
conf = Rack::Handler::Puma.config(->{}, @options)
conf.load
assert_equal ["tcp://0.0.0.0:#{user_port}"], conf.options[:binds]
end
def test_user_port_wins_over_default
user_port = 5001
@options[:Port] = user_port
conf = Rack::Handler::Puma.config(->{}, @options)
conf.load
Implement user_supplied_options behavior. When options are passed to the Puma rack handler it is unknown if the options were set via a framework as a default or via a user. Puma currently has 3 different sources of configuration, the user via command line, the config files, and defaults. Rails 5.1+ will record the values actually specified by the user versus the values specified by the frameworks. It passes these values to the Rack handler and now it's up to Puma to do something with that information. When only framework defaults are passed it will set ``` options[:user_supplied_options] = [] ``` When one or more options are specified by the user such as `:Port` then those keys will be in the array. In that example it will look like this ``` options[:user_supplied_options] = [:Port] ``` This change is 100% backwards compatible. If the framework is older and does not pass this information then the `user_supplied_options` will not be set, in that case we assume all values are user supplied. Internally we accomplish this separation by replacing `LeveledOptions` which was a generic way of specifying options with different priorities with a more explicit `UserFileDefaultOptions` this assumes only 3 levels of options and it will use them in the order supplied (user config wins over file based config wins over defaults). Now instead of using 1 dsl to set all values, we use 3. A user dsl, a file dsl and a Configuration.new` will return all 3 DSLs to the block. It's up to the person using the block to use the correct dsl corresponding to the source of data they are getting.
2017-03-03 22:04:56 +00:00
assert_equal ["tcp://0.0.0.0:#{user_port}"], conf.options[:binds]
end
Implement user_supplied_options behavior. When options are passed to the Puma rack handler it is unknown if the options were set via a framework as a default or via a user. Puma currently has 3 different sources of configuration, the user via command line, the config files, and defaults. Rails 5.1+ will record the values actually specified by the user versus the values specified by the frameworks. It passes these values to the Rack handler and now it's up to Puma to do something with that information. When only framework defaults are passed it will set ``` options[:user_supplied_options] = [] ``` When one or more options are specified by the user such as `:Port` then those keys will be in the array. In that example it will look like this ``` options[:user_supplied_options] = [:Port] ``` This change is 100% backwards compatible. If the framework is older and does not pass this information then the `user_supplied_options` will not be set, in that case we assume all values are user supplied. Internally we accomplish this separation by replacing `LeveledOptions` which was a generic way of specifying options with different priorities with a more explicit `UserFileDefaultOptions` this assumes only 3 levels of options and it will use them in the order supplied (user config wins over file based config wins over defaults). Now instead of using 1 dsl to set all values, we use 3. A user dsl, a file dsl and a Configuration.new` will return all 3 DSLs to the block. It's up to the person using the block to use the correct dsl corresponding to the source of data they are getting.
2017-03-03 22:04:56 +00:00
def test_user_port_wins_over_config
user_port = 5001
file_port = 6001
Implement user_supplied_options behavior. When options are passed to the Puma rack handler it is unknown if the options were set via a framework as a default or via a user. Puma currently has 3 different sources of configuration, the user via command line, the config files, and defaults. Rails 5.1+ will record the values actually specified by the user versus the values specified by the frameworks. It passes these values to the Rack handler and now it's up to Puma to do something with that information. When only framework defaults are passed it will set ``` options[:user_supplied_options] = [] ``` When one or more options are specified by the user such as `:Port` then those keys will be in the array. In that example it will look like this ``` options[:user_supplied_options] = [:Port] ``` This change is 100% backwards compatible. If the framework is older and does not pass this information then the `user_supplied_options` will not be set, in that case we assume all values are user supplied. Internally we accomplish this separation by replacing `LeveledOptions` which was a generic way of specifying options with different priorities with a more explicit `UserFileDefaultOptions` this assumes only 3 levels of options and it will use them in the order supplied (user config wins over file based config wins over defaults). Now instead of using 1 dsl to set all values, we use 3. A user dsl, a file dsl and a Configuration.new` will return all 3 DSLs to the block. It's up to the person using the block to use the correct dsl corresponding to the source of data they are getting.
2017-03-03 22:04:56 +00:00
Dir.mktmpdir do |d|
Dir.chdir(d) do
FileUtils.mkdir("config")
File.open("config/puma.rb", "w") { |f| f << "port #{file_port}" }
Implement user_supplied_options behavior. When options are passed to the Puma rack handler it is unknown if the options were set via a framework as a default or via a user. Puma currently has 3 different sources of configuration, the user via command line, the config files, and defaults. Rails 5.1+ will record the values actually specified by the user versus the values specified by the frameworks. It passes these values to the Rack handler and now it's up to Puma to do something with that information. When only framework defaults are passed it will set ``` options[:user_supplied_options] = [] ``` When one or more options are specified by the user such as `:Port` then those keys will be in the array. In that example it will look like this ``` options[:user_supplied_options] = [:Port] ``` This change is 100% backwards compatible. If the framework is older and does not pass this information then the `user_supplied_options` will not be set, in that case we assume all values are user supplied. Internally we accomplish this separation by replacing `LeveledOptions` which was a generic way of specifying options with different priorities with a more explicit `UserFileDefaultOptions` this assumes only 3 levels of options and it will use them in the order supplied (user config wins over file based config wins over defaults). Now instead of using 1 dsl to set all values, we use 3. A user dsl, a file dsl and a Configuration.new` will return all 3 DSLs to the block. It's up to the person using the block to use the correct dsl corresponding to the source of data they are getting.
2017-03-03 22:04:56 +00:00
@options[:Port] = user_port
conf = Rack::Handler::Puma.config(->{}, @options)
conf.load
Implement user_supplied_options behavior. When options are passed to the Puma rack handler it is unknown if the options were set via a framework as a default or via a user. Puma currently has 3 different sources of configuration, the user via command line, the config files, and defaults. Rails 5.1+ will record the values actually specified by the user versus the values specified by the frameworks. It passes these values to the Rack handler and now it's up to Puma to do something with that information. When only framework defaults are passed it will set ``` options[:user_supplied_options] = [] ``` When one or more options are specified by the user such as `:Port` then those keys will be in the array. In that example it will look like this ``` options[:user_supplied_options] = [:Port] ``` This change is 100% backwards compatible. If the framework is older and does not pass this information then the `user_supplied_options` will not be set, in that case we assume all values are user supplied. Internally we accomplish this separation by replacing `LeveledOptions` which was a generic way of specifying options with different priorities with a more explicit `UserFileDefaultOptions` this assumes only 3 levels of options and it will use them in the order supplied (user config wins over file based config wins over defaults). Now instead of using 1 dsl to set all values, we use 3. A user dsl, a file dsl and a Configuration.new` will return all 3 DSLs to the block. It's up to the person using the block to use the correct dsl corresponding to the source of data they are getting.
2017-03-03 22:04:56 +00:00
assert_equal ["tcp://0.0.0.0:#{user_port}"], conf.options[:binds]
end
Implement user_supplied_options behavior. When options are passed to the Puma rack handler it is unknown if the options were set via a framework as a default or via a user. Puma currently has 3 different sources of configuration, the user via command line, the config files, and defaults. Rails 5.1+ will record the values actually specified by the user versus the values specified by the frameworks. It passes these values to the Rack handler and now it's up to Puma to do something with that information. When only framework defaults are passed it will set ``` options[:user_supplied_options] = [] ``` When one or more options are specified by the user such as `:Port` then those keys will be in the array. In that example it will look like this ``` options[:user_supplied_options] = [:Port] ``` This change is 100% backwards compatible. If the framework is older and does not pass this information then the `user_supplied_options` will not be set, in that case we assume all values are user supplied. Internally we accomplish this separation by replacing `LeveledOptions` which was a generic way of specifying options with different priorities with a more explicit `UserFileDefaultOptions` this assumes only 3 levels of options and it will use them in the order supplied (user config wins over file based config wins over defaults). Now instead of using 1 dsl to set all values, we use 3. A user dsl, a file dsl and a Configuration.new` will return all 3 DSLs to the block. It's up to the person using the block to use the correct dsl corresponding to the source of data they are getting.
2017-03-03 22:04:56 +00:00
end
end
def test_default_log_request_when_no_config_file
conf = Rack::Handler::Puma.config(->{}, @options)
conf.load
assert_equal false, conf.options[:log_requests]
end
def test_file_log_requests_wins_over_default_config
file_log_requests_config = true
@options[:config_files] = [
'test/config/t1_conf.rb'
]
conf = Rack::Handler::Puma.config(->{}, @options)
conf.load
assert_equal file_log_requests_config, conf.options[:log_requests]
end
def test_user_log_requests_wins_over_file_config
user_log_requests_config = false
@options[:log_requests] = user_log_requests_config
@options[:config_files] = [
'test/config/t1_conf.rb'
]
conf = Rack::Handler::Puma.config(->{}, @options)
conf.load
assert_equal user_log_requests_config, conf.options[:log_requests]
end
end
end # if Rack::RELEASE < '3'