puppet-lint 0.2.0.pre1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +1 -14
  3. data/Gemfile +2 -0
  4. data/Rakefile +5 -0
  5. data/bin/puppet-lint +1 -99
  6. data/lib/puppet-lint.rb +4 -12
  7. data/lib/puppet-lint/bin.rb +115 -0
  8. data/lib/puppet-lint/configuration.rb +6 -2
  9. data/lib/puppet-lint/lexer.rb +135 -83
  10. data/lib/puppet-lint/lexer/token.rb +62 -0
  11. data/lib/puppet-lint/plugin.rb +57 -51
  12. data/lib/puppet-lint/plugins.rb +2 -0
  13. data/lib/puppet-lint/plugins/check_classes.rb +161 -45
  14. data/lib/puppet-lint/plugins/check_comments.rb +33 -0
  15. data/lib/puppet-lint/plugins/check_conditionals.rb +8 -10
  16. data/lib/puppet-lint/plugins/check_documentation.rb +41 -0
  17. data/lib/puppet-lint/plugins/check_resources.rb +28 -2
  18. data/lib/puppet-lint/plugins/check_strings.rb +6 -4
  19. data/lib/puppet-lint/plugins/check_variables.rb +1 -1
  20. data/lib/puppet-lint/plugins/check_whitespace.rb +26 -49
  21. data/lib/puppet-lint/tasks/puppet-lint.rb +2 -1
  22. data/lib/puppet-lint/version.rb +1 -1
  23. data/puppet-lint.gemspec +1 -0
  24. data/spec/fixtures/test/manifests/fail.pp +2 -0
  25. data/spec/fixtures/test/manifests/init.pp +3 -0
  26. data/spec/fixtures/test/manifests/warning.pp +2 -0
  27. data/spec/puppet-lint/bin_spec.rb +266 -0
  28. data/spec/puppet-lint/configuration_spec.rb +51 -0
  29. data/spec/puppet-lint/lexer/token_spec.rb +18 -0
  30. data/spec/puppet-lint/lexer_spec.rb +738 -0
  31. data/spec/puppet-lint/{check_classes_spec.rb → plugins/check_classes_spec.rb} +74 -7
  32. data/spec/puppet-lint/plugins/check_comments_spec.rb +40 -0
  33. data/spec/puppet-lint/{check_conditionals_spec.rb → plugins/check_conditionals_spec.rb} +19 -0
  34. data/spec/puppet-lint/plugins/check_documentation_spec.rb +55 -0
  35. data/spec/puppet-lint/{check_resources_spec.rb → plugins/check_resources_spec.rb} +65 -0
  36. data/spec/puppet-lint/{check_strings_spec.rb → plugins/check_strings_spec.rb} +18 -1
  37. data/spec/puppet-lint/{check_variables_spec.rb → plugins/check_variables_spec.rb} +0 -0
  38. data/spec/puppet-lint/plugins/check_whitespace_spec.rb +291 -0
  39. data/spec/puppet-lint_spec.rb +10 -0
  40. data/spec/spec_helper.rb +5 -0
  41. metadata +58 -24
  42. data/spec/puppet-lint/check_whitespace_spec.rb +0 -120
@@ -93,21 +93,28 @@ describe PuppetLint::Plugins::CheckClasses do
93
93
  }
94
94
  end
95
95
 
96
- describe 'class with attrs in order' do
96
+ describe 'parameterised class with a default value' do
97
97
  let(:code) { "class foo($bar, $baz='gronk') { }" }
98
98
 
99
- its(:problems) { should be_empty }
99
+ its(:problems) {
100
+ should only_have_problem({
101
+ :kind => :warning,
102
+ :message => 'parameterised class parameter without a default value',
103
+ :linenumber => 1,
104
+ :column => 11,
105
+ })
106
+ }
100
107
  end
101
108
 
102
- describe 'class with attrs out of order' do
103
- let(:code) { "class foo($bar='baz', $gronk) { }" }
109
+ describe 'parameterised class that inherits from a params class' do
110
+ let(:code) { "class foo($bar = $name) inherits foo::params { }" }
104
111
 
105
112
  its(:problems) {
106
113
  should have_problem({
107
114
  :kind => :warning,
108
- :message => "optional parameter listed before required parameter",
115
+ :message => "class inheriting from params class",
109
116
  :linenumber => 1,
110
- :column => 23,
117
+ :column => 34,
111
118
  })
112
119
  should_not have_problem :kind => :error
113
120
  }
@@ -119,6 +126,12 @@ describe PuppetLint::Plugins::CheckClasses do
119
126
  its(:problems) { should be_empty }
120
127
  end
121
128
 
129
+ describe 'define with parameter that calls a function' do
130
+ let(:code) { "define foo($bar=extlookup($name)) {}" }
131
+
132
+ its(:problems) { should == [] }
133
+ end
134
+
122
135
  describe 'define with attrs out of order' do
123
136
  let(:code) { "define foo($bar='baz', $gronk) { }" }
124
137
 
@@ -174,7 +187,7 @@ describe PuppetLint::Plugins::CheckClasses do
174
187
 
175
188
  describe 'class with parameters accessing local scope' do
176
189
  let(:code) { "
177
- class foo($bar) {
190
+ class foo($bar='UNSET') {
178
191
  $baz = $bar
179
192
  }"
180
193
  }
@@ -320,4 +333,58 @@ describe PuppetLint::Plugins::CheckClasses do
320
333
  let(:fullpath) { '/etc/puppet/modules/bar/manifests/init.pp' }
321
334
  its(:problems) { should be_empty }
322
335
  end
336
+
337
+ describe 'issue-101' do
338
+ let(:code) { "
339
+ define b (
340
+ $foo,
341
+ $bar='',
342
+ $baz={}
343
+ ) { }
344
+ " }
345
+
346
+ its(:problems) { should == [] }
347
+ end
348
+
349
+ describe 'module named foo-bar' do
350
+ let(:code) { 'class foo-bar { }' }
351
+ let(:fullpath) { '/etc/puppet/modules/foo-bar/manifests/init.pp' }
352
+
353
+ its(:problems) do
354
+ should only_have_problem({
355
+ :kind => :warning,
356
+ :message => 'class name containing a dash',
357
+ :linenumber => 1,
358
+ :column => 7,
359
+ })
360
+ end
361
+ end
362
+
363
+ describe 'define named foo-bar' do
364
+ let(:code) { 'define foo::foo-bar { }' }
365
+ let(:fullpath) { '/etc/puppet/modules/foo/manifests/foo-bar.pp' }
366
+
367
+ its(:problems) do
368
+ should only_have_problem({
369
+ :kind => :warning,
370
+ :message => 'defined type name containing a dash',
371
+ :linenumber => 1,
372
+ :column => 8,
373
+ })
374
+ end
375
+ end
376
+
377
+ describe 'class named bar-foo' do
378
+ let(:code) { 'class foo::bar-foo { }' }
379
+ let(:fullpath) { '/etc/puppet/modules/foo/manifests/bar-foo.pp' }
380
+
381
+ its(:problems) do
382
+ should only_have_problem({
383
+ :kind => :warning,
384
+ :message => 'class name containing a dash',
385
+ :linenumber => 1,
386
+ :column => 7,
387
+ })
388
+ end
389
+ end
323
390
  end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe PuppetLint::Plugins::CheckComments do
4
+ subject do
5
+ klass = described_class.new
6
+ fileinfo = {}
7
+ fileinfo[:fullpath] = defined?(fullpath).nil? ? '' : fullpath
8
+ klass.run(fileinfo, code)
9
+ klass
10
+ end
11
+
12
+ describe 'slash comments' do
13
+ let(:code) { "// foo" }
14
+
15
+ its(:problems) do
16
+ should only_have_problem({
17
+ :kind => :warning,
18
+ :message => '// comment found',
19
+ :linenumber => 1,
20
+ :column => 1,
21
+ })
22
+ end
23
+ end
24
+
25
+ describe 'slash asterisk comment' do
26
+ let(:code) { "
27
+ /* foo
28
+ */
29
+ "}
30
+
31
+ its(:problems) do
32
+ should only_have_problem({
33
+ :kind => :warning,
34
+ :message => '/* */ comment found',
35
+ :linenumber => 2,
36
+ :column => 7,
37
+ })
38
+ end
39
+ end
40
+ end
@@ -67,4 +67,23 @@ describe PuppetLint::Plugins::CheckConditionals do
67
67
  })
68
68
  end
69
69
  end
70
+
71
+ describe 'issue-117' do
72
+ let(:code) { "
73
+ $mem = inline_template('<%
74
+ mem,unit = scope.lookupvar(\'::memorysize\').split
75
+ mem = mem.to_f
76
+ # Normalize mem to bytes
77
+ case unit
78
+ when nil: mem *= (1<<0)
79
+ when \'kB\': mem *= (1<<10)
80
+ when \'MB\': mem *= (1<<20)
81
+ when \'GB\': mem *= (1<<30)
82
+ when \'TB\': mem *= (1<<40)
83
+ end
84
+ %><%= mem.to_i %>')
85
+ "}
86
+
87
+ its(:problems) { should == [] }
88
+ end
70
89
  end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe PuppetLint::Plugins::CheckDocumentation do
4
+ subject do
5
+ klass = described_class.new
6
+ fileinfo = {}
7
+ fileinfo[:fullpath] = defined?(fullpath).nil? ? '' : fullpath
8
+ klass.run(fileinfo, code)
9
+ klass
10
+ end
11
+
12
+ describe 'undocumented class' do
13
+ let(:code) { "class test {}" }
14
+
15
+ its(:problems) do
16
+ should only_have_problem({
17
+ :kind => :warning,
18
+ :message => 'class not documented',
19
+ :linenumber => 1,
20
+ :column => 1,
21
+ })
22
+ end
23
+ end
24
+
25
+ describe 'documented class' do
26
+ let(:code) { "
27
+ # foo
28
+ class test {}
29
+ "}
30
+
31
+ its(:problems) { should == [] }
32
+ end
33
+
34
+ describe 'undocumented defined type' do
35
+ let(:code) { "define test {}" }
36
+
37
+ its(:problems) do
38
+ should only_have_problem({
39
+ :kind => :warning,
40
+ :message => 'defined type not documented',
41
+ :linenumber => 1,
42
+ :column => 1,
43
+ })
44
+ end
45
+ end
46
+
47
+ describe 'documented defined type' do
48
+ let(:code) { "
49
+ # foo
50
+ define test {}
51
+ "}
52
+
53
+ its(:problems) { should == [] }
54
+ end
55
+ end
@@ -41,6 +41,20 @@ describe PuppetLint::Plugins::CheckResources do
41
41
  its(:problems) { should be_empty }
42
42
  end
43
43
 
44
+ describe 'file mode undef unquoted' do
45
+ let(:code) { "file { 'foo': mode => undef }" }
46
+
47
+ its(:problems) { should be_empty }
48
+ end
49
+
50
+ describe 'file mode undef quoted' do
51
+ let(:code) { "file { 'foo': mode => 'undef' }" }
52
+
53
+ its(:problems) {
54
+ should only_have_problem :kind => :warning, :message => "mode should be represented as a 4 digit octal value or symbolic mode", :linenumber => 1
55
+ }
56
+ end
57
+
44
58
  describe 'ensure as only attr in a single line resource' do
45
59
  let(:code) { "file { 'foo': ensure => present }" }
46
60
 
@@ -181,4 +195,55 @@ describe PuppetLint::Plugins::CheckResources do
181
195
  should only_have_problem :kind => :warning, :message => "symlink target specified in ensure attr", :linenumber => 3
182
196
  }
183
197
  end
198
+
199
+ # This should really be a lexer test, but I haven't had time to write that
200
+ # test suite yet.
201
+ describe 'issue #116' do
202
+ let(:code) { "
203
+ $config_file_init = $::operatingsystem ? {
204
+ /(?i:Debian|Ubuntu|Mint)/ => '/etc/default/foo',
205
+ default => '/etc/sysconfig/foo',
206
+ }"
207
+ }
208
+
209
+ its(:problems) { should == [] }
210
+ end
211
+
212
+ describe 'resource with duplicate parameters' do
213
+ let(:code) { "
214
+ file { '/tmp/foo':
215
+ ensure => present,
216
+ foo => bar,
217
+ baz => gronk,
218
+ foo => meh,
219
+ }"
220
+ }
221
+
222
+ its(:problems) {
223
+ should only_have_problem({
224
+ :kind => :error,
225
+ :message => 'duplicate parameter found in resource',
226
+ :linenumber => 6,
227
+ :column => 9,
228
+ })
229
+ }
230
+ end
231
+
232
+ describe 'case statement' do
233
+ let(:code) { %{
234
+ case $operatingsystem {
235
+ centos: {
236
+ $version = '1.2.3'
237
+ }
238
+ solaris: {
239
+ $version = '3.2.1'
240
+ }
241
+ default: {
242
+ fail("Module ${module_name} is not supported on ${operatingsystem}")
243
+ }
244
+ }}
245
+ }
246
+
247
+ its(:problems) { should == [] }
248
+ end
184
249
  end
@@ -87,7 +87,7 @@ describe PuppetLint::Plugins::CheckStrings do
87
87
  end
88
88
 
89
89
  describe 'double quoted string containing newline but no variables' do
90
- let(:code) { '"foo\n"' }
90
+ let(:code) { %{"foo\n"} }
91
91
 
92
92
  its(:problems) { should be_empty }
93
93
  end
@@ -155,4 +155,21 @@ describe PuppetLint::Plugins::CheckStrings do
155
155
  })
156
156
  }
157
157
  end
158
+
159
+ describe 'double quoted string with backslash for continuation' do
160
+ let(:code) { %{
161
+ class puppet::master::maintenance (
162
+ ) {
163
+ cron { 'puppet_master_reports_cleanup':
164
+ command => "/usr/bin/find /var/lib/puppet/reports -type f -mtime +15 \
165
+ -delete && /usr/bin/find /var/lib/puppet/reports -mindepth 1 \
166
+ -empty -type d -delete",
167
+ minute => '15',
168
+ hour => '5',
169
+ }
170
+ }
171
+ } }
172
+
173
+ its(:problems) { should == [] }
174
+ end
158
175
  end
@@ -0,0 +1,291 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe PuppetLint::Plugins::CheckWhitespace do
5
+ subject do
6
+ klass = described_class.new
7
+ klass.run(defined?(fullpath).nil? ? {:fullpath => ''} : {:fullpath => fullpath}, code)
8
+ klass
9
+ end
10
+
11
+ describe 'selectors inside a resource' do
12
+ let(:code) { "
13
+ file { 'foo':
14
+ ensure => $ensure,
15
+ require => $ensure ? {
16
+ present => Class['tomcat::install'],
17
+ absent => undef;
18
+ },
19
+ foo => bar,
20
+ }"
21
+ }
22
+
23
+ its(:problems) { should be_empty }
24
+ end
25
+
26
+ describe 'selectors in the middle of a resource' do
27
+ let(:code) { "
28
+ file { 'foo':
29
+ ensure => $ensure ? {
30
+ present => directory,
31
+ absent => undef,
32
+ },
33
+ owner => 'tomcat6',
34
+ }"
35
+ }
36
+
37
+ its(:problems) { should be_empty }
38
+ end
39
+
40
+ describe 'file resource with a source line > 80c' do
41
+ let(:code) { "
42
+ file {
43
+ source => 'puppet:///modules/certificates/etc/ssl/private/wildcard.example.com.crt',
44
+ }"
45
+ }
46
+
47
+ its(:problems) { should be_empty }
48
+ end
49
+
50
+ describe 'selector inside a resource' do
51
+ let(:code) { "
52
+ ensure => $ensure ? {
53
+ present => directory,
54
+ absent => undef,
55
+ },
56
+ owner => 'foo4',
57
+ group => 'foo4',
58
+ mode => '0755'," }
59
+
60
+ its(:problems) { should be_empty }
61
+ end
62
+
63
+ describe 'selector inside a hash inside a resource' do
64
+ let(:code) { "
65
+ server => {
66
+ ensure => ensure => $ensure ? {
67
+ present => directory,
68
+ absent => undef,
69
+ },
70
+ ip => '192.168.1.1'
71
+ },
72
+ owner => 'foo4',
73
+ group => 'foo4',
74
+ mode => '0755'," }
75
+
76
+ its(:problems) { should be_empty }
77
+ end
78
+
79
+
80
+ describe 'length of lines with UTF-8 characters' do
81
+ let(:code) { "
82
+ # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
83
+ # ┃ Configuration ┃
84
+ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛"
85
+ }
86
+ its(:problems) {
87
+ should be_empty
88
+ }
89
+ end
90
+
91
+ describe 'issue #37' do
92
+ let(:code) { "
93
+ class { 'lvs::base':
94
+ virtualeservers => {
95
+ '192.168.2.13' => {
96
+ vport => '11025',
97
+ service => 'smtp',
98
+ scheduler => 'wlc',
99
+ protocol => 'tcp',
100
+ checktype => 'external',
101
+ checkcommand => '/path/to/checkscript',
102
+ real_servers => {
103
+ 'server01' => {
104
+ real_server => '192.168.2.14',
105
+ real_port => '25',
106
+ forwarding => 'masq',
107
+ },
108
+ 'server02' => {
109
+ real_server => '192.168.2.15',
110
+ real_port => '25',
111
+ forwarding => 'masq',
112
+ }
113
+ }
114
+ }
115
+ }
116
+ }"
117
+ }
118
+
119
+ its(:problems) { should be_empty }
120
+ end
121
+
122
+ describe 'single resource with a misaligned =>' do
123
+ let(:code) { "
124
+ file { '/tmp/foo':
125
+ foo => 1,
126
+ bar => 2,
127
+ gronk => 3,
128
+ baz => 4,
129
+ meh => 5,
130
+ }"
131
+ }
132
+
133
+ its(:problems) do
134
+ should have_problem({
135
+ :kind => :warning,
136
+ :message => '=> is not properly aligned',
137
+ :linenumber => 5,
138
+ :column => 15,
139
+ })
140
+ should have_problem({
141
+ :kind => :warning,
142
+ :message => '=> is not properly aligned',
143
+ :linenumber => 6,
144
+ :column => 14,
145
+ })
146
+ end
147
+ end
148
+
149
+ describe 'complex resource with a misaligned =>' do
150
+ let(:code) { "
151
+ file { '/tmp/foo':
152
+ foo => 1,
153
+ bar => $baz ? {
154
+ gronk => 2,
155
+ meh => 3,
156
+ },
157
+ meep => 4,
158
+ bah => 5,
159
+ }"
160
+ }
161
+
162
+ its(:problems) do
163
+ should have_problem({
164
+ :kind => :warning,
165
+ :message => '=> is not properly aligned',
166
+ :linenumber => 4,
167
+ :column => 14,
168
+ })
169
+ should have_problem({
170
+ :kind => :warning,
171
+ :message => '=> is not properly aligned',
172
+ :linenumber => 6,
173
+ :column => 15,
174
+ })
175
+ should have_problem({
176
+ :kind => :warning,
177
+ :message => '=> is not properly aligned',
178
+ :linenumber => 8,
179
+ :column => 14,
180
+ })
181
+ end
182
+ end
183
+
184
+ describe 'multi-resource with a misaligned =>' do
185
+ let(:code) { "
186
+ file {
187
+ '/tmp/foo': ;
188
+ '/tmp/bar':
189
+ foo => 'bar';
190
+ '/tmp/baz':
191
+ gronk => 'bah',
192
+ meh => 'no'
193
+ }"
194
+ }
195
+
196
+ its(:problems) do
197
+ should only_have_problem({
198
+ :kind => :warning,
199
+ :message => '=> is not properly aligned',
200
+ :linenumber => 8,
201
+ :column => 15,
202
+ })
203
+ end
204
+ end
205
+
206
+ describe 'multiple single line resources' do
207
+ let(:code) { "
208
+ file { 'foo': ensure => file }
209
+ package { 'bar': ensure => present }"
210
+ }
211
+
212
+ its(:problems) { should be_empty }
213
+ end
214
+
215
+ describe 'resource with unaligned => in commented line' do
216
+ let(:code) { "
217
+ file { 'foo':
218
+ ensure => directory,
219
+ # purge => true,
220
+ }"
221
+ }
222
+
223
+ its(:problems) { should be_empty }
224
+ end
225
+
226
+ describe 'hard tabs indents' do
227
+ let(:code) { "\tfoo => bar," }
228
+
229
+ its(:problems) {
230
+ should have_problem({
231
+ :kind => :error,
232
+ :message => 'tab character found',
233
+ :linenumber => 1,
234
+ :column => 1,
235
+ })
236
+ }
237
+ end
238
+
239
+ describe 'line with trailing whitespace' do
240
+ let(:code) { "foo " }
241
+
242
+ its(:problems) {
243
+ should have_problem({
244
+ :kind => :error,
245
+ :message => 'trailing whitespace found',
246
+ :linenumber => 1,
247
+ :column => 4,
248
+ })
249
+ }
250
+ end
251
+
252
+ describe '81 character line' do
253
+ let(:code) { 'a' * 81 }
254
+
255
+ its(:problems) {
256
+ should have_problem({
257
+ :kind => :warning,
258
+ :message => 'line has more than 80 characters',
259
+ :linenumber => 1,
260
+ :column => 80,
261
+ })
262
+ }
263
+ end
264
+
265
+ describe 'line indented by 3 spaces' do
266
+ let(:code) { "
267
+ file { 'foo':
268
+ foo => bar,
269
+ }"
270
+ }
271
+
272
+ its(:problems) {
273
+ should have_problem({
274
+ :kind => :error,
275
+ :message => 'two-space soft tabs not used',
276
+ :linenumber => 3,
277
+ :column => 1,
278
+ })
279
+ }
280
+ end
281
+
282
+ describe 'single line resource spread out on multiple lines' do
283
+ let(:code) {"
284
+ file {
285
+ 'foo': ensure => present,
286
+ }"
287
+ }
288
+
289
+ its(:problems) { should == [] }
290
+ end
291
+ end