log2mail 0.0.1.pre3 → 0.0.1.pre4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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