log2mail 0.0.1.pre3 → 0.0.1.pre4

Sign up to get free protection for your applications and to get access to all the features.
@@ -42,7 +42,7 @@ module Log2mail
42
42
  desc "show configuration"
43
43
  def config
44
44
  config_path = ask('configuration path? ').chomp
45
- config = Log2mail::Config.parse_config config_path
45
+ config = Log2mail::Config::ConfigFileHandler.parse_config config_path
46
46
  puts "Defaults:"
47
47
  puts config.defaults
48
48
  puts "Settings:"
data/lib/log2mail/main.rb CHANGED
@@ -81,7 +81,7 @@ Main {
81
81
  option('maxbufsize') { argument_required; cast :int; default 65536 }
82
82
  def run
83
83
  fail "Not starting. Daemon running." if daemon_running? and !params['nofork'].value
84
- config = Log2mail::Config.parse_config @config_path
84
+ config = Log2mail::Config::ConfigFileHandler.parse_config @config_path
85
85
  unless params['nofork'].value
86
86
  Process.daemon
87
87
  $PROGRAM_NAME = Log2mail::PROGNAME
@@ -133,7 +133,7 @@ Main {
133
133
  mode 'configtest' do
134
134
  option('effective', 'e') { description 'show effective settings' }
135
135
  def run
136
- config = Log2mail::Config.parse_config @config_path
136
+ config = Log2mail::Config::ConfigFileHandler.parse_config @config_path
137
137
  puts config.formatted(params['effective'].value)
138
138
  end
139
139
  end
@@ -1,6 +1,6 @@
1
1
  module Log2mail
2
2
  PROGNAME = 'log2mail.rb'
3
- VERSION = "0.0.1.pre3"
3
+ VERSION = "0.0.1.pre4"
4
4
  AUTHOR = "Markus Strauss"
5
5
  AUTHOR_MAIL = "log2mail@dev.sieb.mx"
6
6
  end
@@ -9,7 +9,7 @@ module Log2mail
9
9
  # end
10
10
 
11
11
  def initialize( config, sleeptime )
12
- fail Error, 'Invalid configuration.' unless config.instance_of?(Log2mail::Config)
12
+ fail Error, 'Invalid configuration.' unless config.instance_of?(Config::ConfigFileHandler)
13
13
  @file_patterns = config.file_patterns
14
14
  @files = @file_patterns.keys.map {|f| Log2mail::File.new(f, @file_patterns[f] ) }
15
15
  @sleeptime = sleeptime
data/log2mail.gemspec CHANGED
@@ -32,4 +32,5 @@ Gem::Specification.new do |spec|
32
32
  spec.add_runtime_dependency 'gem-man', '~> 0.3', '>= 0.3.0'
33
33
  spec.add_runtime_dependency 'main', '~> 6.1.0'
34
34
  spec.add_runtime_dependency 'terminal-table'
35
+ spec.add_runtime_dependency 'parslet'
35
36
  end
data/man/log2mail.1 CHANGED
@@ -13,7 +13,7 @@
13
13
  \fBlog2mail\.rb\fR helps having an eye on your systems\' log files\. It efficiently monitors multiple files and reports as soon as specified (regular expression) patterns match\.
14
14
  .
15
15
  .P
16
- On startup, \fBlog2mail\.rb\fR opens all files on the \'watch list\' and seeks to EOF\. All new data are parsed about once a minute (see \fB\-\-sleeptime\fR)\. Matched patterns are reported to the configured mail address(es) (see \fBmailto\fR configuration option)\.
16
+ On startup, \fBlog2mail\.rb\fR opens all files on the \'watch list\' and seeks to EOF\. All new data are parsed about once a minute (see \fB\-\-sleeptime\fR)\. Matched patterns are reported to the configured mail address(es) (see \fBmailto\fR configuration option)\.
17
17
  .
18
18
  .P
19
19
  Log files are reopened automatically when rotated\.
data/man/log2mail.1.ronn CHANGED
@@ -9,7 +9,7 @@ log2mail.rb(1) -- monitors (log) files for patterns and reports hits by mail
9
9
 
10
10
  `log2mail.rb` helps having an eye on your systems' log files. It efficiently monitors multiple files and reports as soon as specified (regular expression) patterns match.
11
11
 
12
- On startup, `log2mail.rb` opens all files on the 'watch list' and seeks to EOF. All new data are parsed about once a minute (see `--sleeptime`). <!-- If necessary, i.e. when multiline patterns are set for the file, every new data is put into a fixed-size buffer. The buffer is rolled over when it gets full. --> Matched patterns are reported to the configured mail address(es) (see `mailto` configuration option).
12
+ On startup, `log2mail.rb` opens all files on the 'watch list' and seeks to EOF. All new data are parsed about once a minute (see `--sleeptime`). Matched patterns are reported to the configured mail address(es) (see `mailto` configuration option).
13
13
 
14
14
  Log files are reopened automatically when rotated.
15
15
 
data/spec/factories.rb CHANGED
@@ -1,51 +1,101 @@
1
1
  require 'tempfile'
2
2
 
3
3
  FactoryGirl.define do
4
- factory :config, class: Log2mail::Config do
5
4
 
5
+ factory :raw_config, class: String do
6
6
  trait :valid do
7
+ initialize_with{ new <<-CONFIG }
8
+ # sample config file for log2mail
9
+ # comments start with '#'
10
+ # see source code doc/Configuration for additional information
11
+
12
+ defaults
13
+ sendtime = 20
14
+ resendtime = 50
15
+ maxlines = 7
16
+ template = /tmp/mail_template
17
+ fromaddr = log2mail
18
+ sendmail = /usr/sbin/sendmail -oi -t
19
+ mailto = global_default_recipient@example.org # new in log2mail.rb
20
+ file = test.log
21
+ pattern = /any/
22
+ pattern = string match
23
+ mailto = special@recipient
24
+ maxlines = 99
25
+ CONFIG
26
+ end
27
+
28
+ trait :valid_without_defaults do
29
+ initialize_with{ new <<-CONFIG }
30
+ file = test.log
31
+ pattern = /any/
32
+ pattern = string match
33
+ mailto = special@recipient
34
+ CONFIG
35
+ end
36
+
37
+ trait :valid_global_mailto_attributes do
38
+ initialize_with{ new <<-CONFIG }
39
+ defaults
40
+ mailto = recipient@test.itstrauss.eu
41
+ fromaddr = log2mail
42
+ file = test.log
43
+ pattern = string pattern
44
+ pattern = /regexp pattern/
45
+ CONFIG
46
+ end
47
+
48
+ trait :valid_global_pattern_attributes do
49
+ initialize_with{ new <<-CONFIG }
50
+ defaults
51
+ pattern = recipient@test.itstrauss.eu
52
+ mailto = special recipient for pattern
53
+ file = test.log
54
+ CONFIG
55
+ end
56
+
57
+ factory :valid_raw_config, traits: [:valid]
58
+ factory :valid_raw_config_without_defaults, traits: [:valid_without_defaults]
59
+ factory :valid_raw_config_with_defaults_with_global_mailto_attributes, traits: [:valid_global_mailto_attributes]
60
+ factory :valid_raw_config_with_defaults_with_global_pattern_attributes, traits: [:valid_global_pattern_attributes]
61
+ end
62
+
63
+ factory :config, class: Log2mail::Config::ConfigFileHandler do
64
+
65
+ factory :valid_config do
7
66
  initialize_with do
8
67
  tmp = Tempfile.new('valid_config')
9
- tmp.write <<-CONFIG
10
- # sample config file for log2mail
11
- # comments start with '#'
12
- # see source code doc/Configuration for additional information
13
-
14
- defaults
15
- sendtime = 20
16
- resendtime = 50
17
- maxlines = 7
18
- template = /tmp/mail_template
19
- fromaddr = log2mail
20
- sendmail = /usr/sbin/sendmail -oi -t
21
- mailto = global_default_recipient@example.org # new in log2mail.rb
22
- file = test.log
23
- pattern = /any/
24
- pattern = string match
25
- mailto = special@recipient
26
- maxlines = 99
27
- CONFIG
68
+ tmp.write build(:valid_raw_config)
28
69
  tmp.close
29
70
  new(tmp.path)
30
71
  end
31
72
  end
32
73
 
33
- trait :valid_without_defaults do
74
+ factory :valid_config_without_defaults do
75
+ initialize_with do
76
+ tmp = Tempfile.new('valid_config')
77
+ tmp.write build(:valid_raw_config_without_defaults)
78
+ tmp.close
79
+ new(tmp.path)
80
+ end
81
+ end
82
+ factory :valid_config_with_defaults_with_global_mailto_attributes do
83
+ initialize_with do
84
+ tmp = Tempfile.new('valid_config')
85
+ tmp.write build(:valid_raw_config_with_defaults_with_global_mailto_attributes)
86
+ tmp.close
87
+ new(tmp.path)
88
+ end
89
+ end
90
+ factory :valid_config_with_defaults_with_global_pattern_attributes do
34
91
  initialize_with do
35
92
  tmp = Tempfile.new('valid_config')
36
- tmp.write <<-CONFIG
37
- file = test.log
38
- pattern = /any/
39
- pattern = string match
40
- mailto = special@recipient
41
- CONFIG
93
+ tmp.write build(:valid_raw_config_with_defaults_with_global_pattern_attributes)
42
94
  tmp.close
43
95
  new(tmp.path)
44
96
  end
45
97
  end
46
98
 
47
- factory :valid_config, traits: [:valid]
48
- factory :valid_config_without_defaults, traits: [:valid_without_defaults]
49
99
  end
50
100
 
51
101
  factory :hit, class: Log2mail::Hit do
@@ -98,4 +148,51 @@ culpa qui officia deserunt mollit anim id est laborum.
98
148
  end
99
149
  end
100
150
 
151
+ sequence :snippet do |n|
152
+ <<-TEXT
153
+ # this is file file#{n}
154
+ file = file#{n}
155
+ pattern = for file#{n}
156
+ mailto = for pattern for file#{n}
157
+ TEXT
158
+ end
159
+
160
+ sequence :filename do |n|
161
+ "config file #{n}"
162
+ end
163
+
164
+
165
+ factory :defaults_snippet, class: Log2mail::Config::ConfigFileSnippet do
166
+ filename = '/config/defaults'
167
+ snippet = <<-TEXT
168
+ # comment
169
+ defaults
170
+ mailto = global_default_recipient@example.org
171
+ TEXT
172
+ initialize_with do
173
+ new(snippet, filename)
174
+ end
175
+ end
176
+
177
+ factory :just_comments_snippet, class: Log2mail::Config::ConfigFileSnippet do
178
+ filename = '/config/comments'
179
+ snippet = <<-TEXT
180
+ # comment
181
+ # other comment
182
+ # even more important comment
183
+ TEXT
184
+ initialize_with do
185
+ new(snippet, filename)
186
+ end
187
+ end
188
+
189
+ factory :config_file_snippet, class: Log2mail::Config::ConfigFileSnippet do
190
+ snippet
191
+ filename
192
+ initialize_with do
193
+ new(snippet, filename)
194
+ end
195
+
196
+ end
197
+
101
198
  end
@@ -1,9 +1,9 @@
1
1
  require 'spec_helper'
2
2
  require 'tempfile'
3
3
 
4
- module Log2mail
4
+ module Log2mail::Config
5
5
 
6
- describe Config do
6
+ describe ConfigFileHandler do
7
7
 
8
8
  subject { build(:valid_config) }
9
9
 
@@ -24,7 +24,7 @@ module Log2mail
24
24
  :template => "/tmp/mail_template",
25
25
  :fromaddr => "log2mail",
26
26
  :sendmail => "/usr/sbin/sendmail -oi -t",
27
- :mailtos => ["global_default_recipient@example.org"],
27
+ :mailtos => {"global_default_recipient@example.org"=>{}},
28
28
  })
29
29
  expect(subject.patterns_for_file('test.log')).to eql(["/any/", "string match"])
30
30
  expect(subject.mailtos_for_pattern('test.log', 'string match')).to eql(["special@recipient"])
@@ -47,6 +47,22 @@ module Log2mail
47
47
  end
48
48
  end
49
49
 
50
+ context 'with defaults with attributes after a global mailto' do
51
+ subject { build(:valid_config_with_defaults_with_global_mailto_attributes) }
52
+ it 'should log a warning' do
53
+ expect($logger).to receive(:warn).with(/Attributes for a global default recipient specified/)
54
+ subject
55
+ end
56
+ end
57
+
58
+ context 'with defaults with attributes after a global pattern' do
59
+ subject { build(:valid_config_with_defaults_with_global_pattern_attributes) }
60
+ it 'should log a warning' do
61
+ expect($logger).to receive(:warn).with(/Attributes for a global default pattern specified/)
62
+ subject
63
+ end
64
+ end
65
+
50
66
  # it { is_expected.to eql build(:config) }
51
67
  end
52
68
 
@@ -98,6 +114,36 @@ module Log2mail
98
114
  end
99
115
  end
100
116
 
117
+ describe '#raw.join' do
118
+ it 'should return the original cat-together config files' do
119
+ expect(subject.raw.join).to eql(<<-EOF)
120
+ # sample config file for log2mail
121
+ # comments start with '#'
122
+ # see source code doc/Configuration for additional information
123
+
124
+ defaults
125
+ sendtime = 20
126
+ resendtime = 50
127
+ maxlines = 7
128
+ template = /tmp/mail_template
129
+ fromaddr = log2mail
130
+ sendmail = /usr/sbin/sendmail -oi -t
131
+ mailto = global_default_recipient@example.org # new in log2mail.rb
132
+ file = test.log
133
+ pattern = /any/
134
+ pattern = string match
135
+ mailto = special@recipient
136
+ maxlines = 99
137
+ EOF
138
+ end
139
+ end
140
+
141
+ describe '#formatted' do
142
+ it 'should return a formatted output of the configuration' do
143
+ expect( subject.formatted ).to be_instance_of(Terminal::Table)
144
+ end
145
+ end
146
+
101
147
  end
102
148
 
103
149
  end
@@ -0,0 +1,467 @@
1
+ require 'spec_helper'
2
+ require 'log2mail/config/parser'
3
+ require 'parslet/rig/rspec'
4
+
5
+ module Log2mail::Config
6
+
7
+ describe Parser do
8
+
9
+ describe 'parse_snippets' do
10
+ it 'should merge the results from multiple files' do
11
+ expect( subject.parse_snippets([
12
+ build(:defaults_snippet),
13
+ build(:config_file_snippet),
14
+ build(:just_comments_snippet),
15
+ build(:config_file_snippet)
16
+ ]).tree ).to eq({
17
+ :defaults=>{:mailtos=>{"global_default_recipient@example.org"=>{}}},
18
+ :files=>{
19
+ "file1"=>{:patterns=>{"for file1"=>{:mailtos=>{"for pattern for file1"=>{}}}}},
20
+ "file2"=>{:patterns=>{"for file2"=>{:mailtos=>{"for pattern for file2"=>{}}}}},
21
+ }
22
+ })
23
+ end
24
+
25
+ it 'should correctly merge configurations for THE SAME file', :focus do
26
+ expect( subject.parse_snippets([
27
+ ConfigFileSnippet.new(<<-TEXT, 'configfile1'),
28
+ file = /file/path
29
+ pattern = pattern1
30
+ mailto = for pattern1
31
+ TEXT
32
+ ConfigFileSnippet.new(<<-TEXT, 'configfile2'),
33
+ file = /file/path
34
+ pattern = pattern2
35
+ mailto = for pattern2
36
+ TEXT
37
+ build(:config_file_snippet)
38
+ ]).tree ).to eq({
39
+ :files=>{
40
+ "/file/path"=>{:patterns=>{
41
+ "pattern1"=>{:mailtos=>{"for pattern1"=>{}}},
42
+ "pattern2"=>{:mailtos=>{"for pattern2"=>{}}} }},
43
+ "file1"=>{:patterns=>{"for file1"=>{:mailtos=>{"for pattern for file1"=>{}}}}},
44
+ }
45
+ })
46
+ end
47
+
48
+ it 'should correctly merge configurations for THE SAME file' do
49
+ expect( subject.parse_snippets([
50
+ ConfigFileSnippet.new(<<-TEXT, 'configfile'),
51
+ file = /file/path
52
+ pattern = pattern1
53
+ mailto = for pattern1
54
+ # file = /file/path
55
+ pattern = pattern2
56
+ mailto = for pattern2
57
+ TEXT
58
+ build(:config_file_snippet)
59
+ ]).tree ).to eq({
60
+ :files=>{
61
+ "/file/path"=>{:patterns=>{
62
+ "pattern1"=>{:mailtos=>{"for pattern1"=>{}}},
63
+ "pattern2"=>{:mailtos=>{"for pattern2"=>{}}} }},
64
+ "file1"=>{:patterns=>{"for file1"=>{:mailtos=>{"for pattern for file1"=>{}}}}},
65
+ }
66
+ })
67
+ end
68
+
69
+ end
70
+
71
+ describe 'invalid configurations should fail' do
72
+ it{ expect{ subject.parse_and_transform("defaults") }.to raise_error(Parslet::ParseFailed) }
73
+ it{ expect{ subject.parse_and_transform("file\n") }.to raise_error(Parslet::ParseFailed)}
74
+ it{ expect{ subject.parse_and_transform("invalid_attribute = some value\n") }.to raise_error(Parslet::ParseFailed)}
75
+ it{ expect{ subject.parse_and_transform("defaults\n invalid_attribute = some value\n") }.to raise_error(Parslet::ParseFailed)}
76
+ it{ expect{ subject.parse_and_transform("pattern = string pattern\n") }.to raise_error(Parslet::ParseFailed)}
77
+ it{ expect{ subject.parse_and_transform("pattern = /regexp pattern/\n") }.to raise_error(Parslet::ParseFailed)}
78
+ end
79
+
80
+ describe '#tree should build hash trees' do
81
+ it{ expect( subject.parse_and_transform("").tree ).to eq({}) }
82
+ it{ expect( subject.parse_and_transform("defaults\n").tree ).to eq(defaults: {}) }
83
+ it{ expect( subject.parse_and_transform("file = /some/where/on/the/path\n").tree ).to eq(files:{'/some/where/on/the/path'=>{}}) }
84
+ it{ expect( subject.parse_and_transform("file = /some/where/on/the/path\npattern = test pattern\n").tree ).to eq \
85
+ files:{'/some/where/on/the/path' => {patterns:{'test pattern'=>{}}}} }
86
+ it{ expect( subject.parse_and_transform("defaults\n fromaddr = some value\n").tree ).to eq(defaults:{fromaddr: 'some value'}) }
87
+ it{ expect( subject.parse_and_transform("defaults\n pattern = string pattern\n").tree ).to eq(defaults:{patterns:{'string pattern'=>{}}}) }
88
+ it{ expect( subject.parse_and_transform("defaults\n pattern = string pattern\n pattern = another pattern\n").tree ).to eq(defaults:{patterns:{'string pattern'=>{}, 'another pattern'=>{}}}) }
89
+ it{ expect( subject.parse_and_transform("defaults\n pattern = \"quoted string pattern \" # with comment\n").tree ).to eq(defaults:{patterns:{'quoted string pattern '=>{}}}) }
90
+ it{ expect( subject.parse_and_transform("defaults\n pattern = \"multiline\n\nquoted string pattern\"\n").tree ).to eq(defaults:{patterns:{"multiline\n\nquoted string pattern"=>{}}}) }
91
+ it{ expect( subject.parse_and_transform(['defaults', "\n", 'pattern = "escaped \\"quoted\\" string pattern"', "\n"].join('') ).tree ).to eq \
92
+ defaults:{patterns:{'escaped "quoted" string pattern'=>{}}} }
93
+ it{ expect( subject.parse_and_transform("defaults\n pattern = /regexp pattern/\n").tree ).to eq(defaults:{patterns:{'/regexp pattern/'=>{}}}) }
94
+ it{ expect( subject.parse_and_transform("defaults\nfile = bla\n").tree ).to eq(defaults: {}, files:{'bla'=>{}})}
95
+
96
+ it{ expect( subject.parse_and_transform("file = file one\npattern = pattern for file one\npattern = second pattern for file one\nfile = file two\npattern = pattern for file two\n").tree ).to eq ({
97
+ files:{
98
+ 'file one' => { patterns:{'pattern for file one'=>{}, 'second pattern for file one'=>{}} },
99
+ 'file two' => { patterns:{'pattern for file two'=>{}} },
100
+ }
101
+ })}
102
+
103
+ it{ expect( subject.parse_and_transform(build(:valid_raw_config)).tree ).to eq({
104
+ defaults:{
105
+ sendtime: 20,
106
+ resendtime: 50,
107
+ maxlines: 7,
108
+ template: '/tmp/mail_template',
109
+ fromaddr: 'log2mail',
110
+ sendmail: '/usr/sbin/sendmail -oi -t',
111
+ mailtos: {'global_default_recipient@example.org'=>{}}},
112
+ files:{
113
+ 'test.log' => {
114
+ patterns:{
115
+ '/any/'=>{},
116
+ 'string match'=>{ mailtos:{'special@recipient'=>{ maxlines: 99} } }
117
+ }
118
+ }
119
+ }
120
+ }) }
121
+
122
+ it{ expect( subject.parse_and_transform(build(:valid_raw_config_without_defaults)).tree ).to \
123
+ eq( files:{'test.log'=>{ patterns:{'/any/'=>{}, 'string match'=>{mailtos:{'special@recipient'=>{}}}} }} )}
124
+ end
125
+
126
+ it{ expect( subject.parse_and_transform("") ).to eq(Config.new) }
127
+
128
+ it{ expect( subject.parse_and_transform("#\n") ).to eq(Config.new) }
129
+
130
+ it{ expect{ subject.parse_and_transform("file = a file\n pattern = a pattern\n \# a comment\n") }.not_to raise_error }
131
+ it{ expect{ subject.parse_and_transform("defaults\n pattern = a pattern\n \# a comment\n") }.not_to raise_error }
132
+
133
+ it 'disallows file -> mailto' do
134
+ expect{ subject.parse_and_transform("file = a file\nmailto = a recipient\n")}.to \
135
+ raise_error Parslet::ParseFailed, /Extra input after last repetition at line 2 char 1/
136
+ end
137
+
138
+ it 'allows file -> pattern' do
139
+ expect{ subject.parse_and_transform("file = a file\npattern = a pattern\n")}.not_to raise_error
140
+ end
141
+
142
+ it 'allows file -> pattern -> mailto' do
143
+ expect{ subject.parse_and_transform("file = a file\npattern = a pattern\nmailto = a mailto\n")}.not_to raise_error
144
+ end
145
+
146
+ it 'allows file -> #comment -> pattern -> mailto' do
147
+ expect{ subject.parse_and_transform("file = a file\n\# a comment\npattern = a pattern\nmailto = a mailto\n")}.not_to raise_error
148
+ end
149
+
150
+ it 'allows file -> pattern -> #comment -> mailto' do
151
+ expect{ subject.parse_and_transform("file = a file\npattern = a pattern\n\# a comment\nmailto = a mailto\n")}.not_to raise_error
152
+ end
153
+
154
+ it 'allows defaults -> mailto' do
155
+ expect{ subject.parse_and_transform("defaults\nmailto = a global mailto\n")}.not_to raise_error
156
+ end
157
+
158
+ it 'allows defaults -> mailto' do
159
+ expect{ subject.parse_and_transform("defaults\nmailto = a global mailto\n")}.not_to raise_error
160
+ end
161
+
162
+ it 'disallows mailto' do
163
+ expect{ subject.parse_and_transform("mailto = a recipient\n")}.to \
164
+ raise_error Parslet::ParseFailed, /Extra input after last repetition at line 1 char 1/
165
+ end
166
+
167
+ it 'allows defaults -> #command -> mailto' do
168
+ expect{ subject.parse_and_transform("defaults\n\# a comment\nmailto = a global mailto\n")}.not_to raise_error
169
+ end
170
+
171
+
172
+ describe 'defaults -> mailto -> attribute' do
173
+ it{ expect{ subject.parse_and_transform("defaults\nmailto = a global mailto\nsendtime = a mailto setting\n")}.not_to raise_error }
174
+ it 'assigns attribute to the global mailto' do
175
+ expect( subject.parse_and_transform("defaults\nmailto = a global mailto\nsendtime = a mailto setting\n").tree).to eq(
176
+ {:defaults=>{:mailtos=>{"a global mailto"=>{:sendtime=>"a mailto setting"}} }})
177
+ end
178
+ end
179
+
180
+
181
+ describe 'defaults -> pattern -> attribute' do
182
+ it{ expect{ subject.parse_and_transform("defaults\npattern = a global pattern\nsendtime = a pattern setting\n")}.not_to raise_error }
183
+ it 'assigns attribute to the global pattern' do
184
+ expect( subject.parse_and_transform("defaults\npattern = a global pattern\nsendtime = a pattern setting\n").tree).to eq(
185
+ {:defaults=>{:patterns=>{"a global pattern"=>{:sendtime=>"a pattern setting"}} }})
186
+ end
187
+ end
188
+
189
+ it{ expect( subject.parse_and_transform("\n") ).to eq(Config.new) }
190
+
191
+ it{ expect( subject.parse_and_transform("defaults\n") ).to eq(Config.new([Section.new(:defaults)])) }
192
+
193
+ it{ expect( subject.parse_and_transform(" defaults \n") ).to eq(Config.new([Section.new(:defaults)])) }
194
+
195
+ it{ expect( subject.parse_and_transform("\# comment\n") ).to eq(Config.new) }
196
+
197
+ it{ expect( subject.parse_and_transform("defaults \# with comment\n") ).to eq(Config.new([Section.new(:defaults)])) }
198
+
199
+ it{ expect( subject.parse_and_transform("file = /some/where/on/the/path\n") ).to eq \
200
+ Config.new [ Section.new(:file, '/some/where/on/the/path') ] }
201
+
202
+ it{ expect( subject.parse_and_transform("file = /some/where/on/the/path\npattern = test pattern\n") ).to eq \
203
+ Config.new [ Section.new(:file, '/some/where/on/the/path', [Section.new(:pattern,'test pattern')]) ] }
204
+
205
+ it{ expect( subject.parse_and_transform("defaults\n fromaddr = some value\n") ).to eq \
206
+ Config.new [ Section.new(:defaults, nil, [Attribute.new(:fromaddr,'some value')]) ] }
207
+
208
+ it 'should collapse multiple default sections' do
209
+ expect( subject.parse_and_transform("defaults\n mailto=recipient@anywhere.com\ndefaults\n") ).to eq \
210
+ Config.new [ Section.new(:defaults, nil, [Section.new(:mailto,'recipient@anywhere.com')]) ]
211
+ end
212
+
213
+ it{ expect( subject.parse_and_transform("defaults\nfile = bla\n") ).to eq \
214
+ Config.new [ Section.new(:defaults,nil), Section.new(:file, 'bla') ] }
215
+
216
+ end
217
+
218
+ describe Transform do
219
+ it 'transforms quoted strings' do
220
+ expect( subject.apply( {:quoted_string=>"multiline\n\nquoted string pattern"} ) ).to eq("multiline\n\nquoted string pattern")
221
+ end
222
+
223
+ it 'transforms unquoted strings' do
224
+ expect( subject.apply( {:unquoted_string=>"a string with spaces at the end "} ) ).to eq('a string with spaces at the end')
225
+ end
226
+
227
+ it 'transforms integers' do
228
+ expect( subject.apply( {:integer=>"123"} ) ).to eq(123)
229
+ end
230
+
231
+ it 'transforms attribute names' do
232
+ INT_OPTIONS.each do |opt|
233
+ rnd_int = rand(2**31)
234
+ expect( subject.apply( {:attribute_name=>opt, :attribute_value=>{:integer=>rnd_int} } ) ).to eq(Attribute.new(opt, rnd_int))
235
+ end
236
+ STR_OPTIONS.each do |opt|
237
+ rnd_string = rand(36**10).to_s(36)
238
+ expect( subject.apply( {:attribute_name=>opt, :attribute_value=>rnd_string } ) ).to eq(Attribute.new(opt, rnd_string))
239
+ end
240
+ PATH_OPTIONS.each do |opt|
241
+ expect( subject.apply( {:attribute_name=>opt, :attribute_value=>'/a/path/string' } ) ).to eq(Attribute.new(opt, '/a/path/string'))
242
+ end
243
+ end
244
+
245
+ it 'transforms section names' do
246
+ expect( subject.apply( {:section_name=>'file', :section_value=>'/a/file/path' } ) ).to eq(Section.new('file', '/a/file/path'))
247
+ expect( subject.apply( {:section_name=>'defaults' } ) ).to eq(Section.new('defaults'))
248
+ end
249
+
250
+ it 'transforms single file section without attributes' do
251
+ expect( subject.apply({
252
+ section:[
253
+ {section_name: 'file', section_value: '/file/path'},
254
+ ]
255
+ } ) ).to eq(
256
+ Section.new(:file, '/file/path' )
257
+ )
258
+ end
259
+
260
+ it 'transforms single file section with attributes' do
261
+ expect( subject.apply({
262
+ section:[
263
+ {section_name: 'file', section_value: '/file/path'},
264
+ {attribute_name: 'sendtime', attribute_value: '123'},
265
+ {attribute_name: 'fromaddr', attribute_value: 'sender@address'},
266
+ ]
267
+ } ) ).to eq(
268
+ Section.new(:file, '/file/path', [Attribute.new(:sendtime,'123'), Attribute.new(:fromaddr,'sender@address')] )
269
+ )
270
+ end
271
+
272
+ it 'transforms simple (non-array) sections' do
273
+ expect( subject.apply(
274
+ {:section=>
275
+ {:section_name=>"pattern",
276
+ :section_value=>{:unquoted_string=>"pattern for file one"}}}
277
+ ) ).to eq(
278
+ Section.new(:pattern, 'pattern for file one' )
279
+ )
280
+ end
281
+
282
+ it 'transforms single file section with subsections' do
283
+ transform = subject.apply(
284
+ {:section=>
285
+ [{:section_name=>"file",
286
+ :section_value=>{:unquoted_string=>"file one"}},
287
+ {:section=>
288
+ {:section_name=>"pattern",
289
+ :section_value=>{:unquoted_string=>"pattern for file one"}}},
290
+ {:section=>
291
+ {:section_name=>"pattern",
292
+ :section_value=>
293
+ {:unquoted_string=>"second pattern for file one"}}}]},
294
+ )
295
+ expect(transform).to eq(
296
+ Section.new(:file, 'file one', [
297
+ Section.new(:pattern, 'pattern for file one'),
298
+ Section.new(:pattern, 'second pattern for file one')] )
299
+ )
300
+ end
301
+
302
+ ### undecided case
303
+ # it 'transforms multiple file sections' do
304
+ # expect( subject.apply({
305
+ # section:[
306
+ # {section_name: 'file', section_value: '/file/path1'},
307
+ # {section_name: 'file', section_value: '/file/path2'},
308
+ # ]
309
+ # } ) ).to eq({
310
+ # files: ['/file/path1', '/file/path2']
311
+ # })
312
+ # end
313
+ #
314
+
315
+ it 'transforms single defaults section' do
316
+ expect( subject.apply({
317
+ section:[
318
+ {section_name: 'defaults'},
319
+ ]
320
+ } ) ).to eq( Section.new(:defaults) )
321
+ end
322
+
323
+ it 'transforms defaults section with attributes' do
324
+ expect( subject.apply({
325
+ section:[
326
+ {section_name: 'defaults'},
327
+ {attribute_name: 'sendtime', attribute_value: '123'},
328
+ {attribute_name: 'fromaddr', attribute_value: 'sender@address'},
329
+ ]
330
+ } ) ).to eq(
331
+ Section.new(:defaults, nil, [Attribute.new(:sendtime,'123'), Attribute.new(:fromaddr, 'sender@address')])
332
+ )
333
+ end
334
+
335
+
336
+ it 'transforms trivial config' do
337
+ expect( subject.apply({
338
+ config:[1,2,3]
339
+ } ) ).to eq(
340
+ Log2mail::Config::Config.new([1,2,3])
341
+ )
342
+ end
343
+
344
+ it 'transforms defaults only config' do
345
+ expect( subject.apply({
346
+ config:[
347
+ section:[
348
+ {section_name: 'defaults'},
349
+ {attribute_name: 'sendtime', attribute_value: '123'},
350
+ {attribute_name: 'fromaddr', attribute_value: 'sender@address'},
351
+ ]
352
+ ]
353
+ } ) ).to eq(Config.new([
354
+ Section.new(:defaults, nil, [Attribute.new(:sendtime,'123'), Attribute.new(:fromaddr, 'sender@address')])
355
+ ]))
356
+ end
357
+
358
+ it 'transforms file only config' do
359
+ expect( subject.apply({
360
+ config:[
361
+ section:[
362
+ {section_name: 'file', section_value: '/file/path1'},
363
+ {attribute_name: 'sendtime', attribute_value: '888'},
364
+ {attribute_name: 'fromaddr', attribute_value: 'other@address'},
365
+ ],
366
+ ]
367
+ } ) ).to eq(Config.new([
368
+ Section.new(:file, '/file/path1', [Attribute.new(:sendtime,'888'), Attribute.new(:fromaddr,'other@address')]),
369
+ ]))
370
+ end
371
+
372
+ it 'transforms combined config' do
373
+ expect( subject.apply(
374
+ {:config=>
375
+ [{:section=>
376
+ [{:section_name=>"defaults"},
377
+ {:attribute_name=>"sendtime",
378
+ :attribute_value=>{:integer=>"20"}},
379
+ {:attribute_name=>"resendtime",
380
+ :attribute_value=>{:integer=>"50"}},
381
+ {:attribute_name=>"maxlines", :attribute_value=>{:integer=>"7"}},
382
+ {:attribute_name=>"template",
383
+ :attribute_value=>{:unquoted_string=>"/tmp/mail_template"}},
384
+ {:attribute_name=>"fromaddr",
385
+ :attribute_value=>{:unquoted_string=>"log2mail"}},
386
+ {:attribute_name=>"sendmail",
387
+ :attribute_value=>{:unquoted_string=>"/usr/sbin/sendmail -oi -t"}},
388
+ {:attribute_name=>"mailto",
389
+ :attribute_value=>
390
+ {:unquoted_string=>"global_default_recipient@example.org "}}]},
391
+ {:section=>
392
+ [{:section_name=>"file",
393
+ :section_value=>{:unquoted_string=>"test.log"}},
394
+ {:section=>
395
+ {:section_name=>"pattern",
396
+ :section_value=>{:unquoted_string=>"/any/"}}},
397
+ {:section=>
398
+ [{:section_name=>"pattern",
399
+ :section_value=>{:unquoted_string=>"string match"}},
400
+ {:section=>
401
+ [{:section_name=>"mailto",
402
+ :section_value=>{:unquoted_string=>"special@recipient"}},
403
+ {:attribute_name=>"maxlines",
404
+ :attribute_value=>{:integer=>"99"}}]}]}]}]}
405
+ )).to eq(
406
+ Log2mail::Config::Config.new([
407
+ Section.new(:defaults, nil, [
408
+ Attribute.new(:sendtime,20),
409
+ Attribute.new(:resendtime, 50),
410
+ Attribute.new(:maxlines, 7),
411
+ Attribute.new(:template, '/tmp/mail_template'),
412
+ Attribute.new(:fromaddr, 'log2mail'),
413
+ Attribute.new(:sendmail, '/usr/sbin/sendmail -oi -t'),
414
+ Attribute.new(:mailto, 'global_default_recipient@example.org')]),
415
+ Section.new(:file, 'test.log', [
416
+ Section.new(:pattern,'/any/'),
417
+ Section.new(:pattern, 'string match', [Section.new(:mailto, 'special@recipient', [Attribute.new(:maxlines, 99)])])])
418
+ ])
419
+ )
420
+ end
421
+
422
+ it 'transforms combined config' do
423
+ expect( subject.apply({
424
+ config:[
425
+ {section:[
426
+ {section_name: 'defaults'},
427
+ {attribute_name: 'sendtime', attribute_value: '123'},
428
+ {attribute_name: 'fromaddr', attribute_value: 'sender@address'},
429
+ ]},
430
+ {section:[
431
+ {section_name: 'file', section_value: '/file/path1'},
432
+ {attribute_name: 'sendtime', attribute_value: '888'},
433
+ {attribute_name: 'fromaddr', attribute_value: 'other@address'},
434
+ ]},
435
+ {section:[
436
+ {section_name: 'file', section_value: '/file/path2'},
437
+ ]}
438
+ ]
439
+ } ) ).to eq(
440
+ Log2mail::Config::Config.new([
441
+ Section.new(:defaults, nil, [Attribute.new(:sendtime,'123'), Attribute.new(:fromaddr, 'sender@address')]),
442
+ Section.new(:file, '/file/path1', [Attribute.new(:sendtime,'888'), Attribute.new(:fromaddr,'other@address')]),
443
+ Section.new(:file, '/file/path2' )
444
+ ])
445
+ )
446
+ end
447
+
448
+ it 'transforms combined SAME FILE config' do
449
+ expect( subject.apply({
450
+ config:[
451
+ {section:[
452
+ {section_name: 'file', section_value: '/the/file/path'},
453
+ {attribute_name: 'sendtime', attribute_value: '888'},
454
+ {attribute_name: 'fromaddr', attribute_value: 'other@address'},
455
+ ]},
456
+ {section:[
457
+ {section_name: 'file', section_value: '/the/file/path'},
458
+ {attribute_name: 'sendtime', attribute_value: '111'},
459
+ ]},
460
+ ]
461
+ } ) ).to eq( #{:files => {"/the/file/path"=>{:sendtime=>"111", :fromaddr=>'other@address'}}})
462
+ Config.new([Section.new(:file, '/the/file/path', [Attribute.new(:sendtime,'111'), Attribute.new(:fromaddr,'other@address')]) ]))
463
+ end
464
+
465
+ end
466
+
467
+ end