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