diff --git a/lib/fluent/config/types.rb b/lib/fluent/config/types.rb index f0b61fa056..2fe5cd4c8e 100644 --- a/lib/fluent/config/types.rb +++ b/lib/fluent/config/types.rb @@ -229,6 +229,14 @@ def self.array_value(val, opts = {}, name = nil) param = if val.is_a?(String) val.start_with?('[') ? JSON.parse(val, Fluent::DEFAULT_JSON_PARSE_OPTIONS) : val.strip.split(/\s*,\s*/) + elsif val.is_a?(Array) + val + elsif val.is_a?(Numeric) || val == true || val == false + # Wrap only the bare scalars that Psych/YAML actually produces + # here (nil is handled by the early return above). Any other + # type (Hash, Symbol, Time, arbitrary objects) falls through and + # still raises "array required" below. + [val] else val end diff --git a/test/config/test_types.rb b/test/config/test_types.rb index 3a6eb8f4ce..8e7691c44d 100644 --- a/test/config/test_types.rb +++ b/test/config/test_types.rb @@ -375,11 +375,27 @@ class TestConfigTypes < ::Test::Unit::TestCase "space in a value w/o qupte" => [["a a","b","c"], 'a a,b,c', {}], "integers" => [[1,2,1], '[1,2,1]', {}], "value_type: :integer w/ quote" => [[1,2,1], '["1","2","1"]', {value_type: :integer}], - "value_type: :integer w/o quote" => [[1,2,1], '1,2,1', {value_type: :integer}]) + "value_type: :integer w/o quote" => [[1,2,1], '1,2,1', {value_type: :integer}], + "bare integer (YAML scalar)" => [[503], 503, {}], + "bare integer w/ value_type" => [[503], 503, {value_type: :integer}], + "bare float (YAML scalar)" => [[1.5], 1.5, {}], + "bare true (YAML scalar)" => [[true], true, {}], + "bare false (YAML scalar)" => [[false], false, {}], + "already an array is untouched" => [[503], [503], {}]) test 'array' do |(expected, val, opts)| assert_equal(expected, Config::ARRAY_TYPE.call(val, opts)) end + data("hash" => [{"key" => "value"}, {}], + "hash w/ value_type" => [{"key" => "1"}, {value_type: :integer}], + "symbol" => [:foo, {}], + "time" => [Time.at(0), {}]) + test 'array w/ unexpected type still raises' do |(val, opts)| + assert_raise(Fluent::ConfigError.new("array required but got #{val.inspect}")) do + Config::ARRAY_TYPE.call(val, opts) + end + end + data('["1","2"]' => [["1","2"], '["1","2"]'], '["3"]' => [["3"], '["3"]']) test 'array w/ default values' do |(expected, val)| diff --git a/test/config/test_yaml_parser.rb b/test/config/test_yaml_parser.rb index 143d5aa5ff..c563c78ac3 100644 --- a/test/config/test_yaml_parser.rb +++ b/test/config/test_yaml_parser.rb @@ -1,5 +1,6 @@ require 'helper' require 'fluent/config/yaml_parser' +require 'fluent/configurable' require 'socket' require 'json' require 'date' @@ -558,4 +559,38 @@ def test_yaml_values assert_equal(:bar, config.elements[0]['symbol2']) assert_equal(/^$/, config.elements[0]['regexp']) end + + class ArrayParamOutput + include Fluent::Configurable + + config_param :retryable_response_codes, :array, value_type: :integer, default: nil + end + + sub_test_case 'array parameter' do + def test_array_param_accepts_bare_scalar + write_config "#{TMP_DIR}/test_array_param_accepts_bare_scalar.yaml", <<~EOS + config: + - match: + $tag: "**" + $type: http + retryable_response_codes: 503 + EOS + config = Fluent::Config::YamlParser.parse("#{TMP_DIR}/test_array_param_accepts_bare_scalar.yaml") + target = ArrayParamOutput.new.configure(config.elements[0]) + assert_equal([503], target.retryable_response_codes) + end + + def test_array_param_accepts_sequence + write_config "#{TMP_DIR}/test_array_param_accepts_sequence.yaml", <<~EOS + config: + - match: + $tag: "**" + $type: http + retryable_response_codes: [502, 503] + EOS + config = Fluent::Config::YamlParser.parse("#{TMP_DIR}/test_array_param_accepts_sequence.yaml") + target = ArrayParamOutput.new.configure(config.elements[0]) + assert_equal([502, 503], target.retryable_response_codes) + end + end end