Merge "Change floating ips management from nova to neutron"
[functest.git] / functest / tests / unit / ci / test_prepare_env.py
1 #!/usr/bin/env python
2
3 # All rights reserved. This program and the accompanying materials
4 # are made available under the terms of the Apache License, Version 2.0
5 # which accompanies this distribution, and is available at
6 # http://www.apache.org/licenses/LICENSE-2.0
7
8 import logging
9 import unittest
10
11 import mock
12
13 from functest.ci import prepare_env
14 from functest.tests.unit import test_utils
15 from functest.utils.constants import CONST
16 from opnfv.utils import constants as opnfv_constants
17
18
19 class PrepareEnvTesting(unittest.TestCase):
20
21     def setUp(self):
22         self.prepare_envparser = prepare_env.PrepareEnvParser()
23         self.db_url_env = 'http://foo/testdb'
24
25     @mock.patch('functest.ci.prepare_env.logger.info')
26     def test_print_separator(self, mock_logger_info):
27         str = "=============================================="
28         prepare_env.print_separator()
29         mock_logger_info.assert_called_once_with(str)
30
31     @mock.patch('functest.ci.prepare_env.logger.info')
32     @mock.patch('functest.ci.prepare_env.logger.warning')
33     def test_check_env_variables_missing_inst_type(self, mock_logger_warn,
34                                                    mock_logger_info):
35         CONST.__setattr__('INSTALLER_TYPE', None)
36         prepare_env.check_env_variables()
37         mock_logger_info.assert_any_call("Checking environment variables"
38                                          "...")
39         mock_logger_warn.assert_any_call("The env variable 'INSTALLER_TYPE'"
40                                          " is not defined.")
41
42     @mock.patch('functest.ci.prepare_env.logger.info')
43     @mock.patch('functest.ci.prepare_env.logger.warning')
44     def test_check_env_variables_missing_inst_ip(self, mock_logger_warn,
45                                                  mock_logger_info):
46         CONST.__setattr__('INSTALLER_IP', None)
47         prepare_env.check_env_variables()
48         mock_logger_info.assert_any_call("Checking environment variables"
49                                          "...")
50         mock_logger_warn.assert_any_call(
51             "The env variable 'INSTALLER_IP' is not defined. It is recommended"
52             " to extract some information from the deployment")
53
54     @mock.patch('functest.ci.prepare_env.logger.info')
55     @mock.patch('functest.ci.prepare_env.logger.warning')
56     def test_check_env_variables_with_inst_ip(self, mock_logger_warn,
57                                               mock_logger_info):
58         CONST.__setattr__('INSTALLER_IP', mock.Mock())
59         prepare_env.check_env_variables()
60         mock_logger_info.assert_any_call("Checking environment variables"
61                                          "...")
62         mock_logger_info.assert_any_call(test_utils.
63                                          SubstrMatch("    INSTALLER_IP="))
64
65     @mock.patch('functest.ci.prepare_env.logger.info')
66     @mock.patch('functest.ci.prepare_env.logger.warning')
67     def test_check_env_variables_missing_scenario(self, mock_logger_warn,
68                                                   mock_logger_info):
69         CONST.__setattr__('DEPLOY_SCENARIO', None)
70         prepare_env.check_env_variables()
71         mock_logger_info.assert_any_call("Checking environment variables"
72                                          "...")
73         mock_logger_warn.assert_any_call("The env variable"
74                                          " 'DEPLOY_SCENARIO' is not defined"
75                                          ". Setting CI_SCENARIO=undefined.")
76
77     @mock.patch('functest.ci.prepare_env.logger.info')
78     @mock.patch('functest.ci.prepare_env.logger.warning')
79     def test_check_env_variables_with_scenario(self, mock_logger_warn,
80                                                mock_logger_info):
81         CONST.__setattr__('DEPLOY_SCENARIO', 'test_scenario')
82         prepare_env.check_env_variables()
83         mock_logger_info.assert_any_call("Checking environment variables"
84                                          "...")
85         mock_logger_info.assert_any_call(test_utils.
86                                          SubstrMatch("DEPLOY_SCENARIO="))
87
88     @mock.patch('functest.ci.prepare_env.logger.info')
89     @mock.patch('functest.ci.prepare_env.logger.warning')
90     def test_check_env_variables_with_ci_debug(self, mock_logger_warn,
91                                                mock_logger_info):
92         CONST.__setattr__('CI_DEBUG', mock.Mock())
93         prepare_env.check_env_variables()
94         mock_logger_info.assert_any_call("Checking environment variables"
95                                          "...")
96         mock_logger_info.assert_any_call(test_utils.
97                                          SubstrMatch("    CI_DEBUG="))
98
99     @mock.patch('functest.ci.prepare_env.logger.info')
100     @mock.patch('functest.ci.prepare_env.logger.warning')
101     def test_check_env_variables_with_node(self, mock_logger_warn,
102                                            mock_logger_info):
103         CONST.__setattr__('NODE_NAME', mock.Mock())
104         prepare_env.check_env_variables()
105         mock_logger_info.assert_any_call("Checking environment variables"
106                                          "...")
107         mock_logger_info.assert_any_call(test_utils.
108                                          SubstrMatch("    NODE_NAME="))
109
110     @mock.patch('functest.ci.prepare_env.logger.info')
111     @mock.patch('functest.ci.prepare_env.logger.warning')
112     def test_check_env_variables_with_build_tag(self, mock_logger_warn,
113                                                 mock_logger_info):
114         CONST.__setattr__('BUILD_TAG', mock.Mock())
115         prepare_env.check_env_variables()
116         mock_logger_info.assert_any_call("Checking environment variables"
117                                          "...")
118
119         mock_logger_info.assert_any_call(test_utils.
120                                          SubstrMatch("    BUILD_TAG="))
121
122     @mock.patch('functest.ci.prepare_env.logger.info')
123     @mock.patch('functest.ci.prepare_env.logger.warning')
124     def test_check_env_variables_with_is_ci_run(self, mock_logger_warn,
125                                                 mock_logger_info):
126         CONST.__setattr__('IS_CI_RUN', mock.Mock())
127         prepare_env.check_env_variables()
128         mock_logger_info.assert_any_call("Checking environment variables"
129                                          "...")
130
131         mock_logger_info.assert_any_call(test_utils.
132                                          SubstrMatch("    IS_CI_RUN="))
133
134     def test_get_deployment_handler_missing_const_vars(self):
135         with mock.patch('functest.ci.prepare_env.'
136                         'factory.Factory.get_handler') as m:
137             CONST.__setattr__('INSTALLER_IP', None)
138             prepare_env.get_deployment_handler()
139             self.assertFalse(m.called)
140
141             CONST.__setattr__('INSTALLER_TYPE', None)
142             prepare_env.get_deployment_handler()
143             self.assertFalse(m.called)
144
145     @mock.patch('functest.ci.prepare_env.logger.debug')
146     def test_get_deployment_handler_missing_print_deploy_info(self,
147                                                               mock_debug):
148         with mock.patch('functest.ci.prepare_env.'
149                         'factory.Factory.get_handler') as m, \
150             mock.patch('functest.ci.prepare_env.'
151                        'ft_utils.get_parameter_from_yaml',
152                        side_effect=ValueError):
153             CONST.__setattr__('INSTALLER_IP', 'test_ip')
154             CONST.__setattr__('INSTALLER_TYPE', 'test_inst_type')
155             opnfv_constants.INSTALLERS = ['test_inst_type']
156             prepare_env.get_deployment_handler()
157             msg = ('Printing deployment info is not supported for '
158                    'test_inst_type')
159             mock_debug.assert_any_call(msg)
160             self.assertFalse(m.called)
161
162     @mock.patch('functest.ci.prepare_env.logger.debug')
163     def test_get_deployment_handler_exception(self, mock_debug):
164         with mock.patch('functest.ci.prepare_env.'
165                         'factory.Factory.get_handler',
166                         side_effect=Exception), \
167             mock.patch('functest.ci.prepare_env.'
168                        'ft_utils.get_parameter_from_yaml'):
169             CONST.__setattr__('INSTALLER_IP', 'test_ip')
170             CONST.__setattr__('INSTALLER_TYPE', 'test_inst_type')
171             opnfv_constants.INSTALLERS = ['test_inst_type']
172             prepare_env.get_deployment_handler()
173             self.assertTrue(mock_debug.called)
174
175     @mock.patch('functest.ci.prepare_env.logger.info')
176     @mock.patch('functest.ci.prepare_env.logger.debug')
177     def test_create_directories_missing_dir(self, mock_logger_debug,
178                                             mock_logger_info):
179         with mock.patch('functest.ci.prepare_env.os.path.exists',
180                         return_value=False), \
181                 mock.patch('functest.ci.prepare_env.os.makedirs') \
182                 as mock_method:
183             prepare_env.create_directories()
184             mock_logger_info.assert_any_call("Creating needed directories...")
185             mock_method.assert_any_call(
186                 CONST.__getattribute__('dir_functest_conf'))
187             mock_method.assert_any_call(
188                 CONST.__getattribute__('dir_functest_data'))
189             mock_method.assert_any_call(
190                 CONST.__getattribute__('dir_functest_images'))
191             mock_logger_info.assert_any_call("    %s created." %
192                                              CONST.__getattribute__(
193                                                  'dir_functest_conf'))
194             mock_logger_info.assert_any_call("    %s created." %
195                                              CONST.__getattribute__(
196                                                  'dir_functest_data'))
197             mock_logger_info.assert_any_call("    %s created." %
198                                              CONST.__getattribute__(
199                                                  'dir_functest_images'))
200
201     @mock.patch('functest.ci.prepare_env.logger.info')
202     @mock.patch('functest.ci.prepare_env.logger.debug')
203     def test_create_directories_with_dir(self, mock_logger_debug,
204                                          mock_logger_info):
205         with mock.patch('functest.ci.prepare_env.os.path.exists',
206                         return_value=True):
207             prepare_env.create_directories()
208             mock_logger_info.assert_any_call("Creating needed directories...")
209             mock_logger_debug.assert_any_call("   %s already exists." %
210                                               CONST.__getattribute__(
211                                                   'dir_functest_conf'))
212             mock_logger_debug.assert_any_call("   %s already exists." %
213                                               CONST.__getattribute__(
214                                                   'dir_functest_data'))
215             mock_logger_debug.assert_any_call("   %s already exists." %
216                                               CONST.__getattribute__(
217                                                   'dir_functest_images'))
218
219     def _get_env_cred_dict(self, os_prefix=''):
220         return {'OS_USERNAME': os_prefix + 'username',
221                 'OS_PASSWORD': os_prefix + 'password',
222                 'OS_AUTH_URL': 'http://test_ip:test_port/v2.0',
223                 'OS_TENANT_NAME': os_prefix + 'tenant_name',
224                 'OS_USER_DOMAIN_NAME': os_prefix + 'user_domain_name',
225                 'OS_PROJECT_DOMAIN_NAME': os_prefix + 'project_domain_name',
226                 'OS_PROJECT_NAME': os_prefix + 'project_name',
227                 'OS_ENDPOINT_TYPE': os_prefix + 'endpoint_type',
228                 'OS_REGION_NAME': os_prefix + 'region_name'}
229
230     @mock.patch('functest.ci.prepare_env.logger.error')
231     @mock.patch('functest.ci.prepare_env.logger.info')
232     @mock.patch('functest.ci.prepare_env.logger.warning')
233     def test_source_rc_missing_rc_file(self, mock_logger_warn,
234                                        mock_logger_info,
235                                        mock_logger_error):
236         with mock.patch('functest.ci.prepare_env.os.path.isfile',
237                         return_value=True), \
238                 mock.patch('functest.ci.prepare_env.os.path.getsize',
239                            return_value=0), \
240                 self.assertRaises(Exception):
241             CONST.__setattr__('openstack_creds', 'test_creds')
242             prepare_env.source_rc_file()
243
244     def test_source_rc_missing_installer_ip(self):
245         with mock.patch('functest.ci.prepare_env.os.path.isfile',
246                         return_value=False), \
247                 self.assertRaises(Exception):
248             CONST.__setattr__('INSTALLER_IP', None)
249             CONST.__setattr__('openstack_creds', 'test_creds')
250             prepare_env.source_rc_file()
251
252     def test_source_rc_missing_installer_type(self):
253         with mock.patch('functest.ci.prepare_env.os.path.isfile',
254                         return_value=False), \
255                 self.assertRaises(Exception):
256             CONST.__setattr__('INSTALLER_IP', 'test_ip')
257             CONST.__setattr__('openstack_creds', 'test_creds')
258             CONST.__setattr__('INSTALLER_TYPE', 'test_type')
259             opnfv_constants.INSTALLERS = []
260             prepare_env.source_rc_file()
261
262     def test_source_rc_missing_os_credfile_ci_inst(self):
263         with mock.patch('functest.ci.prepare_env.os.path.isfile',
264                         return_value=False), \
265                 mock.patch('functest.ci.prepare_env.os.path.getsize'), \
266                 mock.patch('functest.ci.prepare_env.os.path.join'), \
267                 mock.patch('functest.ci.prepare_env.subprocess.Popen') \
268                 as mock_subproc_popen, \
269                 self.assertRaises(Exception):
270             CONST.__setattr__('openstack_creds', None)
271             CONST.__setattr__('INSTALLER_IP', 'test_ip')
272             CONST.__setattr__('INSTALLER_TYPE', 'test_type')
273             opnfv_constants.INSTALLERS = ['test_type']
274
275             process_mock = mock.Mock()
276             attrs = {'communicate.return_value': ('output', 'error'),
277                      'return_code': 1}
278             process_mock.configure_mock(**attrs)
279             mock_subproc_popen.return_value = process_mock
280
281             prepare_env.source_rc_file()
282
283     @mock.patch('functest.ci.prepare_env.logger.debug')
284     def test_patch_file(self, mock_logger_debug):
285         with mock.patch("__builtin__.open", mock.mock_open()), \
286             mock.patch('functest.ci.prepare_env.yaml.safe_load',
287                        return_value={'test_scenario': {'tkey': 'tvalue'}}), \
288             mock.patch('functest.ci.prepare_env.ft_utils.get_functest_yaml',
289                        return_value={'tkey1': 'tvalue1'}), \
290             mock.patch('functest.ci.prepare_env.os.remove') as m, \
291                 mock.patch('functest.ci.prepare_env.yaml.dump'):
292             CONST.__setattr__('DEPLOY_SCENARIO', 'test_scenario')
293             prepare_env.patch_file('test_file')
294             self.assertTrue(m.called)
295
296     @mock.patch('functest.ci.prepare_env.ft_utils.get_functest_yaml',
297                 return_value={'tkey1': 'tvalue1'})
298     @mock.patch('functest.ci.prepare_env.yaml.safe_load',
299                 return_value={'test_scenario': {'tkey': 'tvalue'}})
300     @mock.patch('functest.ci.prepare_env.update_db_url')
301     def test_update_db_url(self, mock_db_url, mock_safe_load,
302                            mock_get_functest_yaml):
303         CONST.__setattr__('DEPLOY_SCENARIO', 'default_scenario')
304         with mock.patch("__builtin__.open", mock.mock_open()), \
305             mock.patch('functest.ci.prepare_env.yaml.dump'), \
306                 mock.patch.dict('functest.ci.prepare_env.os.environ',
307                                 {'TEST_DB_URL': self.db_url_env},
308                                 clear=True):
309             prepare_env.update_config_file()
310             self.assertTrue(mock_db_url.called)
311
312     @mock.patch('functest.ci.prepare_env.logger.info')
313     def test_verify_deployment_error(self, mock_logger_error):
314         mock_popen = mock.Mock()
315         attrs = {'poll.return_value': None,
316                  'stdout.readline.return_value': 'ERROR'}
317         mock_popen.configure_mock(**attrs)
318
319         with mock.patch('functest.ci.prepare_env.print_separator') as m, \
320             mock.patch('functest.ci.prepare_env.subprocess.Popen',
321                        return_value=mock_popen), \
322                 self.assertRaises(Exception) as context:
323             prepare_env.verify_deployment()
324             self.assertTrue(m.called)
325             msg = "Problem while running 'check_os.sh'."
326             mock_logger_error.assert_called_once_with('ERROR')
327             self.assertTrue(msg in context)
328
329     def _get_rally_creds(self):
330         return {"type": "ExistingCloud",
331                 "admin": {"username": 'test_user_name',
332                           "password": 'test_password',
333                           "tenant": 'test_tenant'}}
334
335     @mock.patch('functest.ci.prepare_env.os_utils.get_credentials_for_rally')
336     @mock.patch('functest.ci.prepare_env.logger.info')
337     @mock.patch('functest.ci.prepare_env.ft_utils.execute_command_raise')
338     @mock.patch('functest.ci.prepare_env.ft_utils.execute_command')
339     def test_install_rally(self, mock_exec, mock_exec_raise, mock_logger_info,
340                            mock_os_utils):
341
342         mock_os_utils.return_value = self._get_rally_creds()
343
344         prepare_env.install_rally()
345
346         cmd = "rally deployment destroy opnfv-rally"
347         error_msg = "Deployment %s does not exist." % \
348                     CONST.__getattribute__('rally_deployment_name')
349         mock_logger_info.assert_any_call("Creating Rally environment...")
350         mock_exec.assert_any_call(cmd, error_msg=error_msg, verbose=False)
351
352         cmd = "rally deployment create --file=rally_conf.json --name="
353         cmd += CONST.__getattribute__('rally_deployment_name')
354         error_msg = "Problem while creating Rally deployment"
355         mock_exec_raise.assert_any_call(cmd, error_msg=error_msg)
356
357         cmd = "rally deployment check"
358         error_msg = ("OpenStack not responding or "
359                      "faulty Rally deployment.")
360         mock_exec_raise.assert_any_call(cmd, error_msg=error_msg)
361
362         cmd = "rally deployment list"
363         error_msg = ("Problem while listing "
364                      "Rally deployment.")
365         mock_exec.assert_any_call(cmd, error_msg=error_msg)
366
367         cmd = "rally plugin list | head -5"
368         error_msg = ("Problem while showing "
369                      "Rally plugins.")
370         mock_exec.assert_any_call(cmd, error_msg=error_msg)
371
372     @mock.patch('functest.ci.prepare_env.logger.debug')
373     def test_install_tempest(self, mock_logger_debug):
374         mock_popen = mock.Mock()
375         attrs = {'poll.return_value': None,
376                  'stdout.readline.return_value': '0'}
377         mock_popen.configure_mock(**attrs)
378
379         CONST.__setattr__('tempest_deployment_name', 'test_dep_name')
380         with mock.patch('functest.ci.prepare_env.'
381                         'ft_utils.execute_command_raise',
382                         side_effect=Exception), \
383             mock.patch('functest.ci.prepare_env.subprocess.Popen',
384                        return_value=mock_popen), \
385                 self.assertRaises(Exception):
386             prepare_env.install_tempest()
387             mock_logger_debug.assert_any_call("Tempest test_dep_name"
388                                               " does not exist")
389
390     def test_create_flavor(self):
391         with mock.patch('functest.ci.prepare_env.'
392                         'os_utils.get_or_create_flavor',
393                         return_value=('test_', None)), \
394                 self.assertRaises(Exception) as context:
395             prepare_env.create_flavor()
396             msg = 'Failed to create flavor'
397             self.assertTrue(msg in context)
398
399     @mock.patch('functest.ci.prepare_env.sys.exit')
400     @mock.patch('functest.ci.prepare_env.logger.error')
401     def test_check_environment_missing_file(self, mock_logger_error,
402                                             mock_sys_exit):
403         with mock.patch('functest.ci.prepare_env.os.path.isfile',
404                         return_value=False), \
405                 self.assertRaises(Exception):
406             prepare_env.check_environment()
407
408     @mock.patch('functest.ci.prepare_env.sys.exit')
409     @mock.patch('functest.ci.prepare_env.logger.error')
410     def test_check_environment_with_error(self, mock_logger_error,
411                                           mock_sys_exit):
412         with mock.patch('functest.ci.prepare_env.os.path.isfile',
413                         return_value=True), \
414             mock.patch("__builtin__.open", mock.mock_open(read_data='0')), \
415                 self.assertRaises(Exception):
416             prepare_env.check_environment()
417
418     @mock.patch('functest.ci.prepare_env.logger.info')
419     def test_check_environment_default(self, mock_logger_info):
420         with mock.patch('functest.ci.prepare_env.os.path.isfile',
421                         return_value=True):
422             with mock.patch("__builtin__.open", mock.mock_open(read_data='1')):
423                 prepare_env.check_environment()
424                 mock_logger_info.assert_any_call("Functest environment"
425                                                  " is installed.")
426
427     @mock.patch('functest.ci.prepare_env.check_environment')
428     @mock.patch('functest.ci.prepare_env.create_flavor')
429     @mock.patch('functest.ci.prepare_env.install_tempest')
430     @mock.patch('functest.ci.prepare_env.install_rally')
431     @mock.patch('functest.ci.prepare_env.verify_deployment')
432     @mock.patch('functest.ci.prepare_env.update_config_file')
433     @mock.patch('functest.ci.prepare_env.source_rc_file')
434     @mock.patch('functest.ci.prepare_env.create_directories')
435     @mock.patch('functest.ci.prepare_env.check_env_variables')
436     @mock.patch('functest.ci.prepare_env.logger.info')
437     def test_main_start(self, mock_logger_info, mock_env_var,
438                         mock_create_dir, mock_source_rc, mock_update_config,
439                         mock_verify_depl, mock_install_rally,
440                         mock_install_temp, mock_create_flavor,
441                         mock_check_env):
442         with mock.patch("__builtin__.open", mock.mock_open()) as m:
443             args = {'action': 'start'}
444             self.assertEqual(prepare_env.main(**args), 0)
445             mock_logger_info.assert_any_call("######### Preparing Functest "
446                                              "environment #########\n")
447             self.assertTrue(mock_env_var.called)
448             self.assertTrue(mock_create_dir.called)
449             self.assertTrue(mock_source_rc.called)
450             self.assertTrue(mock_update_config.called)
451             self.assertTrue(mock_verify_depl.called)
452             self.assertTrue(mock_install_rally.called)
453             self.assertTrue(mock_install_temp.called)
454             self.assertTrue(mock_create_flavor.called)
455             m.assert_called_once_with(
456                 CONST.__getattribute__('env_active'), "w")
457             self.assertTrue(mock_check_env.called)
458
459     @mock.patch('functest.ci.prepare_env.check_environment')
460     def test_main_check(self, mock_check_env):
461         args = {'action': 'check'}
462         self.assertEqual(prepare_env.main(**args), 0)
463         self.assertTrue(mock_check_env.called)
464
465     @mock.patch('functest.ci.prepare_env.logger.error')
466     def test_main_no_arg(self, mock_logger_error):
467         args = {'action': 'not_valid'}
468         self.assertEqual(prepare_env.main(**args), -1)
469         mock_logger_error.assert_called_once_with('Argument not valid.')
470
471
472 if __name__ == "__main__":
473     logging.disable(logging.CRITICAL)
474     unittest.main(verbosity=2)