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