fluentd 0.10.45 → 0.10.46

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of fluentd might be problematic. Click here for more details.

Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -1
  3. data/ChangeLog +13 -0
  4. data/Rakefile +18 -2
  5. data/fluentd.gemspec +3 -1
  6. data/lib/fluent/command/fluentd.rb +5 -0
  7. data/lib/fluent/config.rb +17 -333
  8. data/lib/fluent/config/basic_parser.rb +108 -0
  9. data/lib/fluent/config/configure_proxy.rb +145 -0
  10. data/lib/fluent/{config_dsl.rb → config/dsl.rb} +5 -1
  11. data/lib/fluent/config/element.rb +82 -0
  12. data/lib/fluent/config/error.rb +7 -0
  13. data/lib/fluent/config/literal_parser.rb +158 -0
  14. data/lib/fluent/config/parser.rb +96 -0
  15. data/lib/fluent/config/section.rb +115 -0
  16. data/lib/fluent/config/types.rb +86 -0
  17. data/lib/fluent/config/v1_parser.rb +156 -0
  18. data/lib/fluent/configurable.rb +108 -0
  19. data/lib/fluent/engine.rb +4 -3
  20. data/lib/fluent/load.rb +0 -1
  21. data/lib/fluent/parser.rb +15 -5
  22. data/lib/fluent/plugin/buf_memory.rb +13 -5
  23. data/lib/fluent/plugin/in_forward.rb +18 -5
  24. data/lib/fluent/plugin/in_http.rb +4 -2
  25. data/lib/fluent/plugin/in_tail.rb +1 -1
  26. data/lib/fluent/plugin/out_forward.rb +33 -29
  27. data/lib/fluent/registry.rb +76 -0
  28. data/lib/fluent/supervisor.rb +2 -1
  29. data/lib/fluent/test/base.rb +3 -1
  30. data/lib/fluent/version.rb +1 -1
  31. data/spec/config/config_parser_spec.rb +176 -0
  32. data/spec/config/configurable_spec.rb +373 -0
  33. data/spec/config/configure_proxy_spec.rb +96 -0
  34. data/spec/config/dsl_spec.rb +239 -0
  35. data/spec/config/helper.rb +50 -0
  36. data/spec/config/literal_parser_spec.rb +190 -0
  37. data/spec/config/section_spec.rb +97 -0
  38. data/spec/spec_helper.rb +60 -0
  39. data/test/plugin/{in_exec.rb → test_in_exec.rb} +0 -0
  40. data/test/plugin/{in_forward.rb → test_in_forward.rb} +5 -0
  41. data/test/plugin/{in_gc_stat.rb → test_in_gc_stat.rb} +0 -0
  42. data/test/plugin/{in_http.rb → test_in_http.rb} +0 -0
  43. data/test/plugin/{in_object_space.rb → test_in_object_space.rb} +0 -0
  44. data/test/plugin/{in_status.rb → test_in_status.rb} +0 -0
  45. data/test/plugin/{in_stream.rb → test_in_stream.rb} +0 -0
  46. data/test/plugin/{in_syslog.rb → test_in_syslog.rb} +0 -0
  47. data/test/plugin/{in_tail.rb → test_in_tail.rb} +0 -0
  48. data/test/plugin/{out_copy.rb → test_out_copy.rb} +0 -0
  49. data/test/plugin/{out_exec.rb → test_out_exec.rb} +0 -0
  50. data/test/plugin/{out_exec_filter.rb → test_out_exec_filter.rb} +0 -0
  51. data/test/plugin/{out_file.rb → test_out_file.rb} +0 -0
  52. data/test/plugin/{out_forward.rb → test_out_forward.rb} +15 -0
  53. data/test/plugin/{out_roundrobin.rb → test_out_roundrobin.rb} +0 -0
  54. data/test/plugin/{out_stdout.rb → test_out_stdout.rb} +0 -0
  55. data/test/plugin/{out_stream.rb → test_out_stream.rb} +0 -0
  56. data/test/scripts/fluent/plugin/parser_known.rb +3 -0
  57. data/test/{config.rb → test_config.rb} +1 -0
  58. data/test/{configdsl.rb → test_configdsl.rb} +1 -1
  59. data/test/{match.rb → test_match.rb} +0 -0
  60. data/test/{mixin.rb → test_mixin.rb} +0 -0
  61. data/test/{output.rb → test_output.rb} +0 -0
  62. data/test/{parser.rb → test_parser.rb} +22 -5
  63. metadata +114 -51
@@ -69,6 +69,7 @@ module Fluent
69
69
  @suppress_interval = opt[:suppress_interval]
70
70
  @dry_run = opt[:dry_run]
71
71
  @suppress_config_dump = opt[:suppress_config_dump]
72
+ @use_v1_config = opt[:use_v1_config]
72
73
 
73
74
  log_opts = {:suppress_repeated_stacktrace => opt[:suppress_repeated_stacktrace]}
74
75
  @log = LoggerInitializer.new(@log_path, @log_level, @chuser, @chgroup, log_opts)
@@ -282,7 +283,7 @@ module Fluent
282
283
  end
283
284
 
284
285
  def run_configure
285
- Fluent::Engine.parse_config(@config_data, @config_fname, @config_basedir)
286
+ Fluent::Engine.parse_config(@config_data, @config_fname, @config_basedir, @use_v1_config)
286
287
  end
287
288
 
288
289
  def change_privilege
@@ -23,7 +23,9 @@ module Fluent
23
23
  def initialize(klass, &block)
24
24
  if klass.is_a?(Class)
25
25
  if block
26
- klass = klass.dup
26
+ # Create new class for test w/ overwritten methods
27
+ # klass.dup is worse because its ancestors does NOT include original class name
28
+ klass = Class.new(klass)
27
29
  klass.module_eval(&block)
28
30
  end
29
31
  @instance = klass.new
@@ -1,5 +1,5 @@
1
1
  module Fluent
2
2
 
3
- VERSION = '0.10.45'
3
+ VERSION = '0.10.46'
4
4
 
5
5
  end
@@ -0,0 +1,176 @@
1
+ require "json"
2
+ require "config/helper"
3
+ require "fluent/config/error"
4
+ require "fluent/config/basic_parser"
5
+ require "fluent/config/literal_parser"
6
+ require "fluent/config/v1_parser"
7
+
8
+ describe Fluent::Config::V1Parser do
9
+ include_context 'config_helper'
10
+
11
+ def parse_text(text)
12
+ basepath = File.expand_path(File.dirname(__FILE__) + '/../../')
13
+ Fluent::Config::V1Parser.parse(text, '(test)', basepath, nil)
14
+ end
15
+
16
+ def root(*elements)
17
+ if elements.first.is_a?(Fluent::Config::Element)
18
+ attrs = {}
19
+ else
20
+ attrs = elements.shift || {}
21
+ end
22
+ Fluent::Config::Element.new('ROOT', '', attrs, elements)
23
+ end
24
+
25
+ def e(name, arg='', attrs={}, elements=[])
26
+ Fluent::Config::Element.new(name, arg, attrs, elements)
27
+ end
28
+
29
+ describe 'attribute parsing' do
30
+ it "parses attributes" do
31
+ %[
32
+ k1 v1
33
+ k2 v2
34
+ ].should be_parsed_as("k1"=>"v1", "k2"=>"v2")
35
+ end
36
+
37
+ it "parses attribute key always string" do
38
+ "1 1".should be_parsed_as("1" => "1")
39
+ end
40
+
41
+ [
42
+ "_.%$!,",
43
+ "/=~-~@`:?",
44
+ "()*{}.[]",
45
+ ].each do |v|
46
+ it "parses a value with symbol #{v.inspect}" do
47
+ "k #{v}".should be_parsed_as("k" => v)
48
+ end
49
+ end
50
+
51
+ it "ignores spacing around value" do
52
+ " k1 a ".should be_parsed_as("k1" => "a")
53
+ end
54
+
55
+ it "allows spaces in value" do
56
+ "k1 a b c".should be_parsed_as("k1" => "a b c")
57
+ end
58
+
59
+ it "ignores comments after value" do
60
+ " k1 a#comment".should be_parsed_as("k1" => "a")
61
+ end
62
+
63
+ it "allows # in value if quoted" do
64
+ ' k1 "a#comment"'.should be_parsed_as("k1" => "a#comment")
65
+ end
66
+
67
+ it "rejects characters after quoted string" do
68
+ ' k1 "a" 1'.should be_parse_error
69
+ end
70
+ end
71
+
72
+ describe 'element parsing' do
73
+ it do
74
+ "".should be_parsed_as(root)
75
+ end
76
+
77
+ it "accepts empty element" do
78
+ %[
79
+ <test>
80
+ </test>
81
+ ].should be_parsed_as(
82
+ root(
83
+ e("test")
84
+ )
85
+ )
86
+ end
87
+
88
+ it "accepts argument and attributes" do
89
+ %[
90
+ <test var>
91
+ key val
92
+ </test>
93
+ ].should be_parsed_as(root(
94
+ e("test", 'var', {'key'=>"val"})
95
+ ))
96
+ end
97
+
98
+ it "accepts nested elements" do
99
+ %[
100
+ <test var>
101
+ key 1
102
+ <nested1>
103
+ </nested1>
104
+ <nested2>
105
+ </nested2>
106
+ </test>
107
+ ].should be_parsed_as(root(
108
+ e("test", 'var', {'key'=>'val'}, [
109
+ e('nested1'),
110
+ e('nested2')
111
+ ])
112
+ ))
113
+ end
114
+
115
+ [
116
+ "**",
117
+ "*.*",
118
+ "1",
119
+ "_.%$!",
120
+ "/",
121
+ "()*{}.[]",
122
+ ].each do |arg|
123
+ it "parses element argument #{arg.inspect}" do
124
+ %[
125
+ <test #{arg}>
126
+ </test>
127
+ ].should be_parsed_as(root(
128
+ e("test", arg)
129
+ ))
130
+ end
131
+ end
132
+
133
+ it "parses empty element argument to nil" do
134
+ %[
135
+ <test >
136
+ </test>
137
+ ].should be_parsed_as(root(
138
+ e("test", nil)
139
+ ))
140
+ end
141
+
142
+ it "ignores spacing around element argument" do
143
+ %[
144
+ <test a >
145
+ </test>
146
+ ].should be_parsed_as(root(
147
+ e("test", "a")
148
+ ))
149
+ end
150
+
151
+ it "considers comments in element argument" do
152
+ %[
153
+ <test #a>
154
+ </test>
155
+ ].should be_parse_error
156
+ end
157
+
158
+ it "requires line_end after begin tag" do
159
+ %[
160
+ <test></test>
161
+ ].should be_parse_error
162
+ end
163
+
164
+ it "requires line_end after end tag" do
165
+ %[
166
+ <test>
167
+ </test><test>
168
+ </test>
169
+ ].should be_parse_error
170
+ end
171
+ end
172
+
173
+ describe '@include parsing' do
174
+ # TODO
175
+ end
176
+ end
@@ -0,0 +1,373 @@
1
+ require 'fluent/configurable'
2
+ require 'fluent/config/element'
3
+ require 'fluent/config/section'
4
+
5
+ module ConfigurableSpec
6
+ class Base1
7
+ include Fluent::Configurable
8
+
9
+ config_param :node, :string, :default => "node"
10
+ config_param :flag1, :bool, :default => false
11
+ config_param :flag2, :bool, :default => true
12
+
13
+ config_param :name1, :string
14
+ config_param :name2, :string
15
+ config_param :name3, :string, :default => "base1"
16
+ config_param :name4, :string, :default => "base1"
17
+
18
+ def get_all
19
+ [@node, @flag1, @flag2, @name1, @name2, @name3, @name4]
20
+ end
21
+ end
22
+
23
+ class Base2 < Base1
24
+ config_set_default :name2, "base2"
25
+ config_set_default :name4, "base2"
26
+ config_param :name5, :string
27
+ config_param :name6, :string, :default => "base2"
28
+
29
+ def get_all
30
+ ary = super
31
+ ary + [@name5, @name6]
32
+ end
33
+ end
34
+
35
+ class Base3 < Base2
36
+ config_section :node do
37
+ config_param :name, :string, :default => "node"
38
+ config_param :type, :string
39
+ end
40
+ config_section :branch, required: true, multi: true do
41
+ config_argument :name, :string
42
+ config_param :size, :integer, default: 10
43
+ config_section :leaf, required: false, multi: true do
44
+ config_param :weight, :integer
45
+ config_section :worm, param_name: 'worms', multi: true do
46
+ config_param :type, :string, default: 'ladybird'
47
+ end
48
+ end
49
+ end
50
+
51
+ def get_all
52
+ ary = super
53
+ ary + [@branch]
54
+ end
55
+ end
56
+
57
+ class Base4 < Base2
58
+ config_section :node, param_name: :nodes do
59
+ config_argument :num, :integer
60
+ config_param :name, :string, :default => "node"
61
+ config_param :type, :string, :default => "b4"
62
+ end
63
+ config_section :description1, required: false, multi: false do
64
+ config_argument :note, :string, default: "desc1"
65
+ config_param :text, :string
66
+ end
67
+ config_section :description2, required: true, multi: false do
68
+ config_argument :note, :string, default: "desc2"
69
+ config_param :text, :string
70
+ end
71
+ config_section :description3, required: true, multi: true do
72
+ config_argument :note, default: "desc3" do |val|
73
+ "desc3: #{val}"
74
+ end
75
+ config_param :text, :string
76
+ end
77
+
78
+ def get_all
79
+ ary = super
80
+ ary + [@nodes, @description1, @description2, @description3]
81
+ end
82
+ end
83
+ end
84
+
85
+ describe Fluent::Configurable do
86
+ context 'class defined without config_section' do
87
+ describe '#initialize' do
88
+ it 'create instance methods and default values by config_param and config_set_default' do
89
+ obj1 = ConfigurableSpec::Base1.new
90
+ expect(obj1.node).to eql("node")
91
+ expect(obj1.flag1).to eq(false)
92
+ expect(obj1.flag2).to eq(true)
93
+ expect(obj1.name1).to be_nil
94
+ expect(obj1.name2).to be_nil
95
+ expect(obj1.name3).to eql("base1")
96
+ expect(obj1.name4).to eql("base1")
97
+ end
98
+
99
+ it 'create instance methods and default values overwritten by sub class definition' do
100
+ obj2 = ConfigurableSpec::Base2.new
101
+ expect(obj2.node).to eql("node")
102
+ expect(obj2.flag1).to eq(false)
103
+ expect(obj2.flag2).to eq(true)
104
+ expect(obj2.name1).to be_nil
105
+ expect(obj2.name2).to eql("base2")
106
+ expect(obj2.name3).to eql("base1")
107
+ expect(obj2.name4).to eql("base2")
108
+ expect(obj2.name5).to be_nil
109
+ expect(obj2.name6).to eql("base2")
110
+ end
111
+ end
112
+
113
+ describe '#configure' do
114
+ it 'raise errors without any specifications for param without defaults' do
115
+ b2 = ConfigurableSpec::Base2.new
116
+ expect{ b2.configure({}) }.to raise_error(Fluent::ConfigError)
117
+ expect{ b2.configure({"name1" => "t1"}) }.to raise_error(Fluent::ConfigError)
118
+ expect{ b2.configure({"name5" => "t5"}) }.to raise_error(Fluent::ConfigError)
119
+ expect{ b2.configure({"name1" => "t1", "name5" => "t5"}) }.not_to raise_error()
120
+
121
+ expect(b2.get_all).to eql(["node", false, true, "t1", "base2", "base1", "base2", "t5", "base2"])
122
+ end
123
+
124
+ it 'can configure bool values' do
125
+ b2a = ConfigurableSpec::Base2.new
126
+ expect{ b2a.configure({"flag1" => "true", "flag2" => "yes", "name1" => "t1", "name5" => "t5"}) }.not_to raise_error()
127
+ expect(b2a.flag1).to eq(true)
128
+ expect(b2a.flag2).to eq(true)
129
+
130
+ b2b = ConfigurableSpec::Base2.new
131
+ expect{ b2b.configure({"flag1" => "false", "flag2" => "no", "name1" => "t1", "name5" => "t5"}) }.not_to raise_error()
132
+ expect(b2b.flag1).to eq(false)
133
+ expect(b2b.flag2).to eq(false)
134
+ end
135
+
136
+ it 'overwrites values of defaults' do
137
+ b2 = ConfigurableSpec::Base2.new
138
+ b2.configure({"name1" => "t1", "name2" => "t2", "name3" => "t3", "name4" => "t4", "name5" => "t5"})
139
+ expect(b2.name1).to eql("t1")
140
+ expect(b2.name2).to eql("t2")
141
+ expect(b2.name3).to eql("t3")
142
+ expect(b2.name4).to eql("t4")
143
+ expect(b2.name5).to eql("t5")
144
+ expect(b2.name6).to eql("base2")
145
+
146
+ expect(b2.get_all).to eql(["node", false, true, "t1", "t2", "t3", "t4", "t5", "base2"])
147
+ end
148
+ end
149
+ end
150
+
151
+ context 'class defined with config_section' do
152
+ describe '#initialize' do
153
+ it 'create instance methods and default values as nil for params from config_section specified as non-multi' do
154
+ b4 = ConfigurableSpec::Base4.new
155
+ expect(b4.description1).to be_nil
156
+ expect(b4.description2).to be_nil
157
+ end
158
+
159
+ it 'create instance methods and default values as [] for params from config_section specified as multi' do
160
+ b4 = ConfigurableSpec::Base4.new
161
+ expect(b4.description3).to eql([])
162
+ end
163
+
164
+ it 'overwrite base class definition by config_section of sub class definition' do
165
+ b3 = ConfigurableSpec::Base3.new
166
+ expect(b3.node).to eql([])
167
+ end
168
+
169
+ it 'create instance methods and default values by param_name' do
170
+ b4 = ConfigurableSpec::Base4.new
171
+ expect(b4.nodes).to eql([])
172
+ expect(b4.node).to eql("node")
173
+ end
174
+
175
+ it 'create non-required and multi without any specifications' do
176
+ b3 = ConfigurableSpec::Base3.new
177
+ expect(b3.class.merged_configure_proxy.sections[:node].required?).to be_false
178
+ expect(b3.class.merged_configure_proxy.sections[:node].multi?).to be_true
179
+ end
180
+ end
181
+
182
+ describe '#configure' do
183
+ def e(name, arg = '', attrs = {}, elements = [])
184
+ attrs_str_keys = {}
185
+ attrs.each{|key, value| attrs_str_keys[key.to_s] = value }
186
+ Fluent::Config::Element.new(name, arg, attrs_str_keys, elements)
187
+ end
188
+
189
+ BASE_ATTRS = {
190
+ "name1" => "1", "name2" => "2", "name3" => "3",
191
+ "name4" => "4", "name5" => "5", "name6" => "6",
192
+ }
193
+ it 'checks required subsections' do
194
+ b3 = ConfigurableSpec::Base3.new
195
+ # branch sections required
196
+ expect{ b3.configure(e('ROOT', '', BASE_ATTRS, [])) }.to raise_error(Fluent::ConfigError)
197
+
198
+ # branch argument required
199
+ msg = "'<branch ARG>' section requires argument, in section branch"
200
+ expect{ b3.configure(e('ROOT', '', BASE_ATTRS, [e('branch', '')])) }.to raise_error(Fluent::ConfigError, msg)
201
+
202
+ # leaf is not required
203
+ expect{ b3.configure(e('ROOT', '', BASE_ATTRS, [e('branch', 'branch_name')])) }.not_to raise_error()
204
+
205
+ # leaf weight required
206
+ msg = "'weight' parameter is required, in section branch > leaf"
207
+ branch1 = e('branch', 'branch_name', {size: 1}, [e('leaf', '10', {weight: 1})])
208
+ expect{ b3.configure(e('ROOT', '', BASE_ATTRS, [branch1])) }.not_to raise_error()
209
+ branch2 = e('branch', 'branch_name', {size: 1}, [e('leaf', '20')])
210
+ expect{ b3.configure(e('ROOT', '', BASE_ATTRS, [branch1, branch2])) }.to raise_error(Fluent::ConfigError, msg)
211
+ branch3 = e('branch', 'branch_name', {size: 1}, [e('leaf', '10', {weight: 3}), e('leaf', '20')])
212
+ expect{ b3.configure(e('ROOT', '', BASE_ATTRS, [branch3])) }.to raise_error(Fluent::ConfigError, msg)
213
+
214
+ ### worm not required
215
+
216
+ b4 = ConfigurableSpec::Base4.new
217
+
218
+ d1 = e('description1', '', {text:"d1"})
219
+ d2 = e('description2', '', {text:"d2"})
220
+ d3 = e('description3', '', {text:"d3"})
221
+ expect{ b4.configure(e('ROOT', '', BASE_ATTRS, [d1.dup, d2.dup, d3.dup])) }.not_to raise_error()
222
+
223
+ # description1 cannot be specified 2 or more
224
+ msg = "'<description1>' section cannot be written twice or more"
225
+ expect{ b4.configure(e('ROOT', '', BASE_ATTRS, [d1.dup, d2.dup, d1.dup, d3.dup])) }.to raise_error(Fluent::ConfigError, msg)
226
+
227
+ # description2 cannot be specified 2 or more
228
+ msg = "'<description2>' section cannot be written twice or more"
229
+ expect{ b4.configure(e('ROOT', '', BASE_ATTRS, [d1.dup, d2.dup, d3.dup, d2.dup])) }.to raise_error(Fluent::ConfigError, msg)
230
+
231
+ # description3 can be specified 2 or more
232
+ expect{ b4.configure(e('ROOT', '', BASE_ATTRS, [d1.dup, d2.dup, d3.dup, d3.dup])) }.not_to raise_error()
233
+ end
234
+
235
+ it 'constructs confuguration object tree for Base3' do
236
+ conf = e(
237
+ 'ROOT',
238
+ '',
239
+ BASE_ATTRS,
240
+ [
241
+ e('node', '', {type:"1"}), e('node', '', {name:"node2",type:"2"}),
242
+ e('branch', 'b1.*', {}, []),
243
+ e('branch',
244
+ 'b2.*',
245
+ {size: 5},
246
+ [
247
+ e('leaf', 'THIS IS IGNORED', {weight: 55}, []),
248
+ e('leaf', 'THIS IS IGNORED', {weight: 50}, [ e('worm', '', {}) ]),
249
+ e('leaf', 'THIS IS IGNORED', {weight: 50}, [ e('worm', '', {type:"w1"}), e('worm', '', {type:"w2"}) ]),
250
+ ]
251
+ ),
252
+ e('branch',
253
+ 'b3.*',
254
+ {size: "503"},
255
+ [
256
+ e('leaf', 'THIS IS IGNORED', {weight: 55}, []),
257
+ ]
258
+ )
259
+ ],
260
+ )
261
+ b3 = ConfigurableSpec::Base3.new.configure(conf)
262
+
263
+ expect(b3.node).not_to eql("node") # overwritten
264
+
265
+ expect(b3.name1).to eql("1")
266
+ expect(b3.name2).to eql("2")
267
+ expect(b3.name3).to eql("3")
268
+ expect(b3.name4).to eql("4")
269
+ expect(b3.name5).to eql("5")
270
+ expect(b3.name6).to eql("6")
271
+
272
+ expect(b3.node).to be_a(Array)
273
+ expect(b3.node.size).to eql(2)
274
+
275
+ expect(b3.node[0].name).to eql("node")
276
+ expect(b3.node[0].type).to eql("1")
277
+ expect(b3.node[0][:type]).to eq(b3.node[0].type)
278
+ expect(b3.node[1].name).to eql("node2")
279
+ expect(b3.node[1].type).to eql("2")
280
+ expect(b3.node[1][:type]).to eq(b3.node[1].type)
281
+
282
+ expect(b3.branch).to be_a(Array)
283
+ expect(b3.branch.size).to eql(3)
284
+
285
+ expect(b3.branch[0].name).to eql('b1.*')
286
+ expect(b3.branch[0].size).to eql(10)
287
+ expect(b3.branch[0].leaf).to eql([])
288
+
289
+ expect(b3.branch[1].name).to eql('b2.*')
290
+ expect(b3.branch[1].size).to eql(5)
291
+ expect(b3.branch[1].leaf.size).to eql(3)
292
+ expect(b3.branch[1][:leaf]).to eq(b3.branch[1].leaf)
293
+
294
+ expect(b3.branch[1].leaf[0].weight).to eql(55)
295
+ expect(b3.branch[1].leaf[0].worms.size).to eql(0)
296
+
297
+ expect(b3.branch[1].leaf[1].weight).to eql(50)
298
+ expect(b3.branch[1].leaf[1].worms.size).to eql(1)
299
+ expect(b3.branch[1].leaf[1].worms[0].type).to eql("ladybird")
300
+
301
+ expect(b3.branch[1].leaf[2].weight).to eql(50)
302
+ expect(b3.branch[1].leaf[2].worms.size).to eql(2)
303
+ expect(b3.branch[1].leaf[2].worms[0].type).to eql("w1")
304
+ expect(b3.branch[1].leaf[2].worms[1].type).to eql("w2")
305
+
306
+ expect(b3.branch[2].name).to eql('b3.*')
307
+ expect(b3.branch[2].size).to eql(503)
308
+ expect(b3.branch[2].leaf.size).to eql(1)
309
+ expect(b3.branch[2].leaf[0].weight).to eql(55)
310
+ end
311
+
312
+ it 'constructs confuguration object tree for Base4' do
313
+ conf = e(
314
+ 'ROOT',
315
+ '',
316
+ BASE_ATTRS,
317
+ [
318
+ e('node', '1', {type:"1"}), e('node', '2', {name:"node2"}),
319
+ e('description3', '', {text:"dddd3-1"}),
320
+ e('description2', 'd-2', {text:"dddd2"}),
321
+ e('description1', '', {text:"dddd1"}),
322
+ e('description3', 'd-3', {text:"dddd3-2"}),
323
+ e('description3', 'd-3a', {text:"dddd3-3"}),
324
+ e('node', '4', {type:"four"}),
325
+ ],
326
+ )
327
+ b4 = ConfigurableSpec::Base4.new.configure(conf)
328
+
329
+ expect(b4.node).to eql("node")
330
+
331
+ expect(b4.name1).to eql("1")
332
+ expect(b4.name2).to eql("2")
333
+ expect(b4.name3).to eql("3")
334
+ expect(b4.name4).to eql("4")
335
+ expect(b4.name5).to eql("5")
336
+ expect(b4.name6).to eql("6")
337
+
338
+ expect(b4.nodes).to be_a(Array)
339
+ expect(b4.nodes.size).to eql(3)
340
+ expect(b4.nodes[0].num).to eql(1)
341
+ expect(b4.nodes[0].name).to eql("node")
342
+ expect(b4.nodes[0].type).to eql("1")
343
+ expect(b4.nodes[1].num).to eql(2)
344
+ expect(b4.nodes[1].name).to eql("node2")
345
+ expect(b4.nodes[1].type).to eql("b4")
346
+ expect(b4.nodes[2].num).to eql(4)
347
+ expect(b4.nodes[2].name).to eql("node")
348
+ expect(b4.nodes[2].type).to eql("four")
349
+
350
+ # e('description3', '', {text:"dddd3-1"}),
351
+ # e('description3', 'd-3', {text:"dddd3-2"}),
352
+ # e('description3', 'd-3a', {text:"dddd3-3"}),
353
+
354
+ expect(b4.description1).to be_a(Fluent::Config::Section)
355
+ expect(b4.description1.note).to eql("desc1")
356
+ expect(b4.description1.text).to eql("dddd1")
357
+
358
+ expect(b4.description2).to be_a(Fluent::Config::Section)
359
+ expect(b4.description2.note).to eql("d-2")
360
+ expect(b4.description2.text).to eql("dddd2")
361
+
362
+ expect(b4.description3).to be_a(Array)
363
+ expect(b4.description3.size).to eql(3)
364
+ expect(b4.description3[0].note).to eql('desc3')
365
+ expect(b4.description3[0].text).to eql('dddd3-1')
366
+ expect(b4.description3[1].note).to eql('desc3: d-3')
367
+ expect(b4.description3[1].text).to eql('dddd3-2')
368
+ expect(b4.description3[2].note).to eql('desc3: d-3a')
369
+ expect(b4.description3[2].text).to eql('dddd3-3')
370
+ end
371
+ end
372
+ end
373
+ end