Fixes clustering to use template instead of exec
[integration/packaging/puppet-opendaylight.git] / spec / spec_helper.rb
1 require 'puppetlabs_spec_helper/module_spec_helper'
2 require 'rspec-puppet-facts'
3 include RspecPuppetFacts
4
5 # Customize filters to ignore 3rd-party code
6 # If the coverage report shows not-our-code results, add it here
7 custom_filters = [
8   'Anchor[java::end]',
9   'Stage[setup]',
10   'Anchor[java::begin:]',
11   'Archive::Download[opendaylight.tar.gz]',
12   'Archive::Download[opendaylight-systemd.tar.gz]',
13   'Archive::Extract[opendaylight]',
14   'Archive::Extract[opendaylight-systemd]',
15   'Class[Java::Config]',
16   'Class[Java::Params]',
17   'Class[Stdlib::Stages]',
18   'Class[Stdlib]',
19   'Exec[download archive opendaylight.tar.gz and check sum]',
20   'Exec[download archive opendaylight-systemd.tar.gz and check sum]',
21   'Exec[opendaylight unpack]',
22   'Exec[opendaylight-systemd unpack]',
23   'Exec[rm-on-error-opendaylight.tar.gz]',
24   'Exec[rm-on-error-opendaylight-systemd.tar.gz]',
25   'Exec[reload_systemd_units]',
26   'Exec[update-java-alternatives]',
27   'Package[curl]',
28   'Stage[deploy]',
29   'Stage[deploy_app]',
30   'Stage[deploy_infra]',
31   'Stage[runtime]',
32   'Stage[setup_app]',
33   'Stage[setup_infra]',
34 ]
35 RSpec::Puppet::Coverage.filters.push(*custom_filters)
36
37 #
38 # NB: This is a library of helper fns used by the rspec-puppet tests
39 #
40
41 # Tests that are common to all possible configurations
42 def generic_tests()
43   # Confirm that module compiles
44   it { should compile }
45   it { should compile.with_all_deps }
46
47   # Confirm presence of classes
48   it { should contain_class('opendaylight') }
49   it { should contain_class('opendaylight::params') }
50   it { should contain_class('opendaylight::install') }
51   it { should contain_class('opendaylight::config') }
52   it { should contain_class('opendaylight::service') }
53
54   # Confirm relationships between classes
55   it { should contain_class('opendaylight::install').that_comes_before('Class[opendaylight::config]') }
56   it { should contain_class('opendaylight::config').that_requires('Class[opendaylight::install]') }
57   it { should contain_class('opendaylight::config').that_notifies('Class[opendaylight::service]') }
58   it { should contain_class('opendaylight::service').that_subscribes_to('Class[opendaylight::config]') }
59   it { should contain_class('opendaylight::service').that_comes_before('Class[opendaylight]') }
60   it { should contain_class('opendaylight').that_requires('Class[opendaylight::service]') }
61
62   # Confirm presence of generic resources
63   it { should contain_service('opendaylight') }
64   it { should contain_file('org.apache.karaf.features.cfg') }
65
66   # Confirm properties of generic resources
67   # NB: These hashes don't work with Ruby 1.8.7, but we
68   #   don't support 1.8.7 so that's okay. See issue #36.
69   it {
70     should contain_service('opendaylight').with(
71       'ensure'      => 'running',
72       'enable'      => 'true',
73       'hasstatus'   => 'true',
74       'hasrestart'  => 'true',
75     )
76   }
77   it {
78     should contain_file('org.apache.karaf.features.cfg').with(
79       'ensure'      => 'file',
80       'path'        => '/opt/opendaylight/etc/org.apache.karaf.features.cfg',
81       'owner'   => 'odl',
82       'group'   => 'odl',
83     )
84   }
85 end
86
87 # Shared tests that specialize in testing Karaf feature installs
88 def karaf_feature_tests(options = {})
89   # Extract params
90   # NB: This default list should be the same as the one in opendaylight::params
91   # TODO: Remove this possible source of bugs^^
92   default_features = options.fetch(:default_features, ['config', 'standard', 'region', 'package', 'kar', 'ssh', 'management'])
93   extra_features = options.fetch(:extra_features, [])
94
95   # The order of this list concat matters
96   features = default_features + extra_features
97   features_csv = features.join(',')
98
99   # Confirm properties of Karaf features config file
100   # NB: These hashes don't work with Ruby 1.8.7, but we
101   #   don't support 1.8.7 so that's okay. See issue #36.
102   it {
103     should contain_file('org.apache.karaf.features.cfg').with(
104       'ensure'      => 'file',
105       'path'        => '/opt/opendaylight/etc/org.apache.karaf.features.cfg',
106       'owner'   => 'odl',
107       'group'   => 'odl',
108     )
109   }
110   it {
111     should contain_file_line('featuresBoot').with(
112       'path'  => '/opt/opendaylight/etc/org.apache.karaf.features.cfg',
113       'line'  => "featuresBoot=#{features_csv}",
114       'match' => '^featuresBoot=.*$',
115     )
116   }
117 end
118
119 # Shared tests that specialize in testing ODL's REST port config
120 def odl_rest_port_tests(options = {})
121   # Extract params
122   # NB: This default value should be the same as one in opendaylight::params
123   # TODO: Remove this possible source of bugs^^
124   odl_rest_port = options.fetch(:odl_rest_port, 8080)
125
126   # Confirm properties of ODL REST port config file
127   # NB: These hashes don't work with Ruby 1.8.7, but we
128   #   don't support 1.8.7 so that's okay. See issue #36.
129   it {
130     should contain_file('jetty.xml').with(
131       'ensure'      => 'file',
132       'path'        => '/opt/opendaylight/etc/jetty.xml',
133       'owner'   => 'odl',
134       'group'   => 'odl',
135       'content'     => /Property name="jetty.port" default="#{odl_rest_port}"/
136     )
137   }
138 end
139
140 def log_level_tests(options = {})
141   # Extract params
142   # NB: This default value should be the same as one in opendaylight::params
143   # TODO: Remove this possible source of bugs^^
144   log_levels = options.fetch(:log_levels, {})
145
146   if log_levels.empty?
147     # Should contain log level config file
148     it {
149       should_not contain_file_line('logger-org.opendaylight.ovsdb')
150     }
151   else
152     # Verify each custom log level config entry
153     log_levels.each_pair do |logger, level|
154       it {
155         should contain_file_line("logger-#{logger}").with(
156           'ensure' => 'present',
157           'path' => '/opt/opendaylight/etc/org.ops4j.pax.logging.cfg',
158           'line' => "log4j.logger.#{logger}=#{level}",
159         )
160       }
161     end
162   end
163 end
164
165 def enable_ha_tests(options = {})
166   # Extract params
167   enable_ha = options.fetch(:enable_ha, false)
168   odl_bind_ip = options.fetch(:odl_bind_ip, '0.0.0.0')
169   ha_node_ips = options.fetch(:ha_node_ips, [])
170   ha_db_modules = options.fetch(:ha_db_modules, { 'default' => false })
171   # HA_NODE_IPS size
172   ha_node_count = ha_node_ips.size
173
174   if (enable_ha) && (ha_node_count < 2)
175     # Check for HA_NODE_COUNT < 2
176     fail("Number of HA nodes less than 2: #{ha_node_count} and HA Enabled")
177   end
178
179   if enable_ha
180     ha_node_index = ha_node_ips.index(odl_bind_ip)
181     it {
182       should contain_file('akka.conf').with(
183         'path'    => '/opt/opendaylight/configuration/initial/akka.conf',
184         'ensure'  => 'file',
185         'owner'   => 'odl',
186         'group'   => 'odl',
187         'content' => /roles\s*=\s*\["member-#{ha_node_index}"\]/
188       )
189     }
190
191     ha_db_modules.each do |mod, urn|
192       it { should contain_file('module-shards.conf').with(
193         'path'    => '/opt/opendaylight/configuration/initial/module-shards.conf',
194         'ensure'  => 'file',
195         'owner'   => 'odl',
196         'group'   => 'odl',
197         'content' => /name = "#{mod}"/
198       )}
199       if mod == 'default'
200         it { should contain_file('modules.conf').with(
201           'path'    => '/opt/opendaylight/configuration/initial/modules.conf',
202           'ensure'  => 'file',
203           'owner'   => 'odl',
204           'group'   => 'odl'
205         )}
206       else
207         it { should contain_file('modules.conf').with(
208           'path'    => '/opt/opendaylight/configuration/initial/modules.conf',
209           'ensure'  => 'file',
210           'owner'   => 'odl',
211           'group'   => 'odl',
212           'content' => /name = "#{mod}"/,
213         )}
214       end
215     end
216   else
217     it {
218       should_not contain_file('akka.conf')
219       should_not contain_file('module-shards.conf')
220       should_not contain_file('modules.conf')
221       }
222   end
223 end
224
225 def rpm_install_tests(options = {})
226   # Extract params
227   rpm_repo = options.fetch(:rpm_repo, 'opendaylight-6-testing')
228   java_opts = options.fetch(:java_opts, '-Djava.net.preferIPv4Stack=true')
229
230   # Default to CentOS 7 Yum repo URL
231
232   # Confirm presence of RPM-related resources
233   it { should contain_yumrepo(rpm_repo) }
234   it { should contain_package('opendaylight') }
235
236   # Confirm relationships between RPM-related resources
237   it { should contain_package('opendaylight').that_requires("Yumrepo[#{rpm_repo}]") }
238   it { should contain_yumrepo(rpm_repo).that_comes_before('Package[opendaylight]') }
239
240   # Confirm properties of RPM-related resources
241   # NB: These hashes don't work with Ruby 1.8.7, but we
242   #   don't support 1.8.7 so that's okay. See issue #36.
243   it {
244     should contain_yumrepo(rpm_repo).with(
245       'enabled'     => '1',
246       'gpgcheck'    => '0',
247       'descr'       => 'OpenDaylight SDN Controller',
248       'baseurl'     => "http://cbs.centos.org/repos/nfv7-#{rpm_repo}/$basearch/os/",
249     )
250   }
251   it {
252     should contain_package('opendaylight').with(
253       'ensure'   => 'present',
254     )
255   }
256
257   it {
258     should contain_file_line('java_options_systemd').with(
259       'ensure' => 'present',
260       'path' => '/usr/lib/systemd/system/opendaylight.service',
261       'line' => "Environment=_JAVA_OPTIONS=\'#{java_opts}\'",
262       'after' => 'ExecStart=/opt/opendaylight/bin/start',
263     )
264   }
265 end
266
267 def deb_install_tests(options = {})
268   # Extract params
269   deb_repo = options.fetch(:deb_repo, 'ppa:odl-team/carbon')
270
271   # Confirm the presence of Deb-related resources
272   it { should contain_apt__ppa(deb_repo) }
273   it { should contain_package('opendaylight') }
274
275   # Confirm relationships between Deb-related resources
276   it { should contain_package('opendaylight').that_requires("Apt::Ppa[#{deb_repo}]") }
277   it { should contain_apt__ppa(deb_repo).that_comes_before('Package[opendaylight]') }
278
279   # Confirm presence of Deb-related resources
280   it {
281     should contain_package('opendaylight').with(
282       'ensure'   => 'present',
283     )
284   }
285 end
286
287 # Shared tests for unsupported OSs
288 def unsupported_os_tests(options = {})
289   # Extract params
290   expected_msg = options.fetch(:expected_msg)
291   rpm_repo = options.fetch(:rpm_repo, 'opendaylight-6-testing')
292
293   # Confirm that classes fail on unsupported OSs
294   it { expect { should contain_class('opendaylight') }.to raise_error(Puppet::Error, /#{expected_msg}/) }
295   it { expect { should contain_class('opendaylight::install') }.to raise_error(Puppet::Error, /#{expected_msg}/) }
296   it { expect { should contain_class('opendaylight::config') }.to raise_error(Puppet::Error, /#{expected_msg}/) }
297   it { expect { should contain_class('opendaylight::service') }.to raise_error(Puppet::Error, /#{expected_msg}/) }
298
299   # Confirm that other resources fail on unsupported OSs
300   it { expect { should contain_yumrepo(rpm_repo) }.to raise_error(Puppet::Error, /#{expected_msg}/) }
301   it { expect { should contain_package('opendaylight') }.to raise_error(Puppet::Error, /#{expected_msg}/) }
302   it { expect { should contain_service('opendaylight') }.to raise_error(Puppet::Error, /#{expected_msg}/) }
303   it { expect { should contain_file('org.apache.karaf.features.cfg') }.to raise_error(Puppet::Error, /#{expected_msg}/) }
304 end
305
306 # Shared tests that specialize in testing security group mode
307 def enable_sg_tests(sg_mode='stateful', os_release)
308   # Extract params
309   # NB: This default value should be the same as one in opendaylight::params
310   # TODO: Remove this possible source of bugs^^
311
312   it { should contain_file('/opt/opendaylight/etc/opendaylight') }
313   it { should contain_file('/opt/opendaylight/etc/opendaylight/datastore')}
314   it { should contain_file('/opt/opendaylight/etc/opendaylight/datastore/initial')}
315   it { should contain_file('/opt/opendaylight/etc/opendaylight/datastore/initial/config')}
316
317   if os_release != '7.3' and sg_mode == 'stateful'
318     # Confirm sg_mode becomes learn
319     it {
320       should contain_file('netvirt-aclservice-config.xml').with(
321         'ensure'      => 'file',
322         'path'        => '/opt/opendaylight/etc/opendaylight/datastore/initial/config/netvirt-aclservice-config.xml',
323         'owner'   => 'odl',
324         'group'   => 'odl',
325         'content'     => /learn/
326       )
327     }
328   else
329     # Confirm other sg_mode is passed correctly
330     it {
331       should contain_file('netvirt-aclservice-config.xml').with(
332         'ensure'      => 'file',
333         'path'        => '/opt/opendaylight/etc/opendaylight/datastore/initial/config/netvirt-aclservice-config.xml',
334         'owner'   => 'odl',
335         'group'   => 'odl',
336         'content'     => /#{sg_mode}/
337       )
338     }
339   end
340 end
341
342 # Shared tests that specialize in testing VPP routing node config
343 def vpp_routing_node_tests(options = {})
344   # Extract params
345   # NB: This default list should be the same as the one in opendaylight::params
346   # TODO: Remove this possible source of bugs^^
347   routing_node = options.fetch(:routing_node, '')
348
349   if routing_node.empty?
350     it { should_not contain_file('org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.startup.cfg') }
351     it { should_not contain_file_line('routing-node') }
352   else
353     # Confirm properties of Karaf config file
354     # NB: These hashes don't work with Ruby 1.8.7, but we
355     #   don't support 1.8.7 so that's okay. See issue #36.
356     it {
357       should contain_file('org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.startup.cfg').with(
358         'ensure'      => 'file',
359         'path'        => '/opt/opendaylight/etc/org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.startup.cfg',
360         'owner'   => 'odl',
361         'group'   => 'odl',
362       )
363     }
364     it {
365       should contain_file_line('routing-node').with(
366         'path'  => '/opt/opendaylight/etc/org.opendaylight.groupbasedpolicy.neutron.vpp.mapper.startup.cfg',
367         'line'  => "routing-node=#{routing_node}",
368         'match' => '^routing-node=.*$',
369       )
370     }
371   end
372 end
373
374 # ODL username/password tests
375 def username_password_tests(username, password)
376
377   it {
378     should contain_odl_user(username).with(
379       :password => password
380     )
381   }
382 end