require_relative '../helper'
require 'fluent/config/element'
require 'fluent/config/configure_proxy'
require 'fluent/configurable'
require 'pp'
class TestConfigElement < ::Test::Unit::TestCase
def element(name = 'ROOT', arg = '', attrs = {}, elements = [], unused = nil)
Fluent::Config::Element.new(name, arg, attrs, elements, unused)
end
sub_test_case '#elements=' do
test 'elements can be set by others' do
e = element()
assert_equal [], e.elements
e1 = element('e1')
e2 = element('e2')
e.elements = [e1, e2]
assert_equal [e1, e2], e.elements
end
end
sub_test_case '#elements' do
setup do
@c1 = element('source')
@c2 = element('source', 'yay')
@c3 = element('match', 'test.**')
@c4 = element('label', '@mytest', {}, [ element('filter', '**'), element('match', '**') ])
children = [@c1, @c2, @c3, @c4]
@e = Fluent::Config::Element.new('ROOT', '', {}, children)
end
test 'returns all elements without arguments' do
assert_equal [@c1, @c2, @c3, @c4], @e.elements
end
test 'returns elements with specified names' do
assert_equal [@c1, @c2, @c3], @e.elements('source', 'match')
assert_equal [@c3, @c4], @e.elements('match', 'label')
end
test 'returns elements with specified name, and arg if specified' do
assert_equal [@c1, @c2], @e.elements(name: 'source')
assert_equal [@c2], @e.elements(name: 'source', arg: 'yay')
end
test 'keyword argument name/arg and names are exclusive' do
assert_raise ArgumentError do
@e.elements('source', name: 'match')
end
assert_raise ArgumentError do
@e.elements('source', 'match', name: 'label', arg: '@mytest')
end
end
test 'specifying only arg without name is invalid' do
assert_raise ArgumentError do
@e.elements(arg: '@mytest')
end
end
end
sub_test_case '#initialize' do
test 'creates object with blank attrs and elements' do
e = element('ROOT', '', {}, [])
assert_equal([], e.elements)
end
test 'creates object which contains attrs and elements' do
e = element('ROOT', '', {"k1" => "v1", "k2" => "v2"}, [
element('test', 'mydata', {'k3' => 'v3'}, [])
])
assert_equal('ROOT', e.name)
assert_equal('', e.arg)
assert_equal('v1', e["k1"])
assert_equal('v2', e["k2"])
assert_equal(1, e.elements.size)
e.each_element('test') do |el|
assert_equal('test', el.name)
assert_equal('mydata', el.arg)
assert_equal('v3', el["k3"])
end
end
test 'creates object which contains attrs, elements and unused' do
e = element('ROOT', '', {"k1" => "v1", "k2" => "v2", "k4" => "v4"}, [
element('test', 'mydata', {'k3' => 'v3'}, [])
], "k3")
assert_equal("k3", e.unused)
assert_equal('ROOT', e.name)
assert_equal('', e.arg)
assert_equal('v1', e["k1"])
assert_equal('v2', e["k2"])
assert_equal('v4', e["k4"])
assert_equal(1, e.elements.size)
e.each_element('test') do |el|
assert_equal('test', el.name)
assert_equal('mydata', el.arg)
assert_equal('v3', el["k3"])
end
assert_equal("k3", e.unused)
end
end
sub_test_case "@unused" do
sub_test_case '#[] has side effect for @unused' do
test 'without unused argument' do
e = element('ROOT', '', {"k1" => "v1", "k2" => "v2", "k4" => "v4"}, [
element('test', 'mydata', {'k3' => 'v3'}, [])
])
assert_equal(["k1", "k2", "k4"], e.unused)
assert_equal('v1', e["k1"])
assert_equal(["k2", "k4"], e.unused)
assert_equal('v2', e["k2"])
assert_equal(["k4"], e.unused)
assert_equal('v4', e["k4"])
assert_equal([], e.unused)
end
test 'with unused argument' do
e = element('ROOT', '', {"k1" => "v1", "k2" => "v2", "k4" => "v4"}, [
element('test', 'mydata', {'k3' => 'v3'}, [])
], ["k4"])
assert_equal(["k4"], e.unused)
assert_equal('v1', e["k1"])
assert_equal(["k4"], e.unused)
assert_equal('v2', e["k2"])
assert_equal(["k4"], e.unused)
assert_equal('v4', e["k4"])
# only consume for "k4"
assert_equal([], e.unused)
end
end
end
sub_test_case '#add_element' do
test 'elements can be set by #add_element' do
e = element()
assert_equal [], e.elements
e.add_element('e1', '')
e.add_element('e2', '')
assert_equal [element('e1', ''), element('e2', '')], e.elements
end
end
sub_test_case '#==' do
sub_test_case 'compare with two element objects' do
test 'equal' do
e1 = element('ROOT', '', {}, [])
e2 = element('ROOT', '', {}, [])
assert_true(e1 == e2)
end
data("differ args" => [Fluent::Config::Element.new('ROOT', '', {}, []),
Fluent::Config::Element.new('ROOT', 'mydata', {}, [])],
"differ keys" => [Fluent::Config::Element.new('ROOT', 'mydata', {}, []),
Fluent::Config::Element.new('ROOT', 'mydata', {"k1" => "v1"}, [])],
"differ elemnts" =>
[Fluent::Config::Element.new('ROOT', 'mydata', {"k1" => "v1"}, []),
Fluent::Config::Element.new('ROOT', 'mydata', {"k1" => "v1"}, [
Fluent::Config::Element.new('test', 'mydata', {'k3' => 'v3'}, [])
])])
test 'not equal' do |data|
e1, e2 = data
assert_false(e1 == e2)
end
end
end
sub_test_case '#+' do
test 'can merge 2 elements: object side is primary' do
e1 = element('ROOT', 'mydata', {"k1" => "v1"}, [])
e2 = element('ROOT', 'mydata2', {"k1" => "ignored", "k2" => "v2"}, [
element('test', 'ext', {'k3' => 'v3'}, [])
])
e = e1 + e2
assert_equal('ROOT', e.name)
assert_equal('mydata', e.arg)
assert_equal('v1', e['k1'])
assert_equal('v2', e['k2'])
assert_equal(1, e.elements.size)
e.each_element('test') do |el|
assert_equal('test', el.name)
assert_equal('ext', el.arg)
assert_equal('v3', el["k3"])
end
end
end
sub_test_case '#check_not_fetched' do
sub_test_case 'without unused' do
test 'can get attribute keys and original Config::Element' do
e = element('ROOT', 'mydata', {"k1" => "v1"}, [])
e.check_not_fetched { |key, elem|
assert_equal("k1", key)
assert_equal(e, elem)
}
end
end
sub_test_case 'with unused' do
test 'can get unused marked attribute keys and original Config::Element' do
e = element('ROOT', 'mydata', {"k1" => "v1", "k2" => "unused", "k3" => "k3"})
e.unused = "k2"
e.check_not_fetched { |key, elem|
assert_equal("k2", key)
assert_equal(e, elem)
}
end
end
end
sub_test_case '#has_key?' do
test 'can get boolean with key name' do
e = element('ROOT', 'mydata', {"k1" => "v1"}, [])
assert_true(e.has_key?("k1"))
assert_false(e.has_key?("noexistent"))
end
end
sub_test_case '#to_s' do
data("without v1_config" => [false, <<-CONF
k1 v1
k2 "stringVal"
k2 v2
CONF
],
"with v1_config" => [true, <<-CONF
k1 v1
k2 "stringVal"
k2 v2
CONF
],
)
test 'dump config element with #to_s' do |data|
v1_config, expected = data
e = element('ROOT', '', {'k1' => 'v1', "k2" =>"\"stringVal\""}, [
element('test', 'ext', {'k2' => 'v2'}, [])
])
e.v1_config = v1_config
dump = expected
assert_not_equal(e.inspect, e.to_s)
assert_equal(dump, e.to_s)
end
end
sub_test_case '#inspect' do
test 'dump config element with #inspect' do
e = element('ROOT', '', {'k1' => 'v1'}, [
element('test', 'ext', {'k2' => 'v2'}, [])
])
dump = <<-CONF
name:ROOT, arg:, {\"k1\"=>\"v1\"}, [name:test, arg:ext, {\"k2\"=>\"v2\"}, []]
CONF
assert_not_equal(e.to_s, e.inspect)
assert_equal(dump.chomp, e.inspect)
end
end
sub_test_case 'for sections which has secret parameter' do
setup do
@type_lookup = ->(type){ Fluent::Configurable.lookup_type(type) }
p1 = Fluent::Config::ConfigureProxy.new(:match, type_lookup: @type_lookup)
p1.config_param :str1, :string
p1.config_param :str2, :string, secret: true
p1.config_param :enum1, :enum, list: [:a, :b, :c]
p1.config_param :enum2, :enum, list: [:a, :b, :c], secret: true
p1.config_param :bool1, :bool
p1.config_param :bool2, :bool, secret: true
p1.config_param :int1, :integer
p1.config_param :int2, :integer, secret: true
p1.config_param :float1, :float
p1.config_param :float2, :float, secret: true
p2 = Fluent::Config::ConfigureProxy.new(:match, type_lookup: @type_lookup)
p2.config_param :size1, :size
p2.config_param :size2, :size, secret: true
p2.config_param :time1, :time
p2.config_param :time2, :time, secret: true
p2.config_param :array1, :array
p2.config_param :array2, :array, secret: true
p2.config_param :hash1, :hash
p2.config_param :hash2, :hash, secret: true
p1.config_section :mysection do
config_param :str1, :string
config_param :str2, :string, secret: true
config_param :enum1, :enum, list: [:a, :b, :c]
config_param :enum2, :enum, list: [:a, :b, :c], secret: true
config_param :bool1, :bool
config_param :bool2, :bool, secret: true
config_param :int1, :integer
config_param :int2, :integer, secret: true
config_param :float1, :float
config_param :float2, :float, secret: true
config_param :size1, :size
config_param :size2, :size, secret: true
config_param :time1, :time
config_param :time2, :time, secret: true
config_param :array1, :array
config_param :array2, :array, secret: true
config_param :hash1, :hash
config_param :hash2, :hash, secret: true
end
params = {
'str1' => 'aaa', 'str2' => 'bbb', 'enum1' => 'a', 'enum2' => 'b', 'bool1' => 'true', 'bool2' => 'yes',
'int1' => '1', 'int2' => '2', 'float1' => '1.0', 'float2' => '0.5', 'size1' => '1k', 'size2' => '1m',
'time1' => '5m', 'time2' => '3h', 'array1' => 'a,b,c', 'array2' => 'd,e,f',
'hash1' => 'a:1,b:2', 'hash2' => 'a:2,b:4',
'unknown1' => 'yay', 'unknown2' => 'boo',
}
e2 = Fluent::Config::Element.new('mysection', '', params.dup, [])
e2.corresponding_proxies << p1.sections.values.first
@e = Fluent::Config::Element.new('match', '**', params, [e2])
@e.corresponding_proxies << p1
@e.corresponding_proxies << p2
end
sub_test_case '#to_masked_element' do
test 'returns a new element object which has masked values for secret parameters and elements' do
e = @e.to_masked_element
assert_equal 'aaa', e['str1']
assert_equal 'xxxxxx', e['str2']
assert_equal 'a', e['enum1']
assert_equal 'xxxxxx', e['enum2']
assert_equal 'true', e['bool1']
assert_equal 'xxxxxx', e['bool2']
assert_equal '1', e['int1']
assert_equal 'xxxxxx', e['int2']
assert_equal '1.0', e['float1']
assert_equal 'xxxxxx', e['float2']
assert_equal '1k', e['size1']
assert_equal 'xxxxxx', e['size2']
assert_equal '5m', e['time1']
assert_equal 'xxxxxx', e['time2']
assert_equal 'a,b,c', e['array1']
assert_equal 'xxxxxx', e['array2']
assert_equal 'a:1,b:2', e['hash1']
assert_equal 'xxxxxx', e['hash2']
assert_equal 'yay', e['unknown1']
assert_equal 'boo', e['unknown2']
e2 = e.elements.first
assert_equal 'aaa', e2['str1']
assert_equal 'xxxxxx', e2['str2']
assert_equal 'a', e2['enum1']
assert_equal 'xxxxxx', e2['enum2']
assert_equal 'true', e2['bool1']
assert_equal 'xxxxxx', e2['bool2']
assert_equal '1', e2['int1']
assert_equal 'xxxxxx', e2['int2']
assert_equal '1.0', e2['float1']
assert_equal 'xxxxxx', e2['float2']
assert_equal '1k', e2['size1']
assert_equal 'xxxxxx', e2['size2']
assert_equal '5m', e2['time1']
assert_equal 'xxxxxx', e2['time2']
assert_equal 'a,b,c', e2['array1']
assert_equal 'xxxxxx', e2['array2']
assert_equal 'a:1,b:2', e2['hash1']
assert_equal 'xxxxxx', e2['hash2']
assert_equal 'yay', e2['unknown1']
assert_equal 'boo', e2['unknown2']
end
end
sub_test_case '#secret_param?' do
test 'returns boolean which shows values of given key will be masked' do
assert !@e.secret_param?('str1')
assert @e.secret_param?('str2')
assert !@e.elements.first.secret_param?('str1')
assert @e.elements.first.secret_param?('str2')
end
end
sub_test_case '#param_type' do
test 'returns parameter type which are registered in corresponding proxy' do
assert_equal :string, @e.param_type('str1')
assert_equal :string, @e.param_type('str2')
assert_equal :enum, @e.param_type('enum1')
assert_equal :enum, @e.param_type('enum2')
assert_nil @e.param_type('unknown1')
assert_nil @e.param_type('unknown2')
end
end
# sub_test_case '#dump_value'
sub_test_case '#dump_value' do
test 'dumps parameter_name and values with leading indentation' do
assert_equal "str1 aaa\n", @e.dump_value("str1", @e["str1"], "")
assert_equal "str2 xxxxxx\n", @e.dump_value("str2", @e["str2"], "")
end
end
end
sub_test_case '#set_target_worker' do
test 'set target_worker_id recursively' do
e = element('label', '@mytest', {}, [ element('filter', '**'), element('match', '**', {}, [ element('store'), element('store') ]) ])
e.set_target_worker_id(1)
assert_equal 1, e.target_worker_id
assert_equal 1, e.elements[0].target_worker_id
assert_equal 1, e.elements[1].target_worker_id
assert_equal 1, e.elements[1].elements[0].target_worker_id
assert_equal 1, e.elements[1].elements[1].target_worker_id
end
end
sub_test_case '#for_every_workers?' do
test 'has target_worker_id' do
e = element()
e.set_target_worker_id(1)
assert_false e.for_every_workers?
end
test "doesn't have target_worker_id" do
e = element()
assert e.for_every_workers?
end
end
sub_test_case '#for_this_workers?' do
test 'target_worker_id == current worker_id' do
e = element()
e.set_target_worker_id(0)
assert e.for_this_worker?
end
test 'target_worker_id != current worker_id' do
e = element()
e.set_target_worker_id(1)
assert_false e.for_this_worker?
end
test "doesn't have target_worker_id" do
e = element()
assert_false e.for_this_worker?
end
end
sub_test_case '#for_another_worker?' do
test 'target_worker_id == current worker_id' do
e = element()
e.set_target_worker_id(0)
assert_false e.for_another_worker?
end
test 'target_worker_id != current worker_id' do
e = element()
e.set_target_worker_id(1)
assert e.for_another_worker?
end
test "doesn't have target_worker_id" do
e = element()
assert_false e.for_another_worker?
end
end
sub_test_case '#pretty_print' do
test 'prints inspect to pp object' do
q = PP.new
e = element()
e.pretty_print(q)
assert_equal e.inspect, q.output
end
end
end