import os from cloudinit.analyze.__main__ import (analyze_boot, get_parser) from cloudinit.tests.helpers import CiTestCase, mock from cloudinit.analyze.show import dist_check_timestamp, SystemctlReader, \ FAIL_CODE, CONTAINER_CODE err_code = (FAIL_CODE, -1, -1, -1) class TestDistroChecker(CiTestCase): @mock.patch('cloudinit.util.system_info', return_value={'dist': ('', '', ''), 'system': ''}) @mock.patch('cloudinit.util.get_linux_distro', return_value=('', '', '')) @mock.patch('cloudinit.util.is_FreeBSD', return_value=False) def test_blank_distro(self, m_sys_info, m_get_linux_distro, m_free_bsd): self.assertEqual(err_code, dist_check_timestamp()) @mock.patch('cloudinit.util.system_info', return_value={'dist': ('', '', '')}) @mock.patch('cloudinit.util.get_linux_distro', return_value=('', '', '')) @mock.patch('cloudinit.util.is_FreeBSD', return_value=True) def test_freebsd_gentoo_cant_find(self, m_sys_info, m_get_linux_distro, m_is_FreeBSD): self.assertEqual(err_code, dist_check_timestamp()) @mock.patch('cloudinit.subp.subp', return_value=(0, 1)) def test_subp_fails(self, m_subp): self.assertEqual(err_code, dist_check_timestamp()) class TestSystemCtlReader(CiTestCase): def test_systemctl_invalid_property(self): reader = SystemctlReader('dummyProperty') with self.assertRaises(RuntimeError): reader.parse_epoch_as_float() def test_systemctl_invalid_parameter(self): reader = SystemctlReader('dummyProperty', 'dummyParameter') with self.assertRaises(RuntimeError): reader.parse_epoch_as_float() @mock.patch('cloudinit.subp.subp', return_value=('U=1000000', None)) def test_systemctl_works_correctly_threshold(self, m_subp): reader = SystemctlReader('dummyProperty', 'dummyParameter') self.assertEqual(1.0, reader.parse_epoch_as_float()) thresh = 1.0 - reader.parse_epoch_as_float() self.assertTrue(thresh < 1e-6) self.assertTrue(thresh > (-1 * 1e-6)) @mock.patch('cloudinit.subp.subp', return_value=('U=0', None)) def test_systemctl_succeed_zero(self, m_subp): reader = SystemctlReader('dummyProperty', 'dummyParameter') self.assertEqual(0.0, reader.parse_epoch_as_float()) @mock.patch('cloudinit.subp.subp', return_value=('U=1', None)) def test_systemctl_succeed_distinct(self, m_subp): reader = SystemctlReader('dummyProperty', 'dummyParameter') val1 = reader.parse_epoch_as_float() m_subp.return_value = ('U=2', None) reader2 = SystemctlReader('dummyProperty', 'dummyParameter') val2 = reader2.parse_epoch_as_float() self.assertNotEqual(val1, val2) @mock.patch('cloudinit.subp.subp', return_value=('100', None)) def test_systemctl_epoch_not_splittable(self, m_subp): reader = SystemctlReader('dummyProperty', 'dummyParameter') with self.assertRaises(IndexError): reader.parse_epoch_as_float() @mock.patch('cloudinit.subp.subp', return_value=('U=foobar', None)) def test_systemctl_cannot_convert_epoch_to_float(self, m_subp): reader = SystemctlReader('dummyProperty', 'dummyParameter') with self.assertRaises(ValueError): reader.parse_epoch_as_float() class TestAnalyzeBoot(CiTestCase): def set_up_dummy_file_ci(self, path, log_path): infh = open(path, 'w+') infh.write('2019-07-08 17:40:49,601 - util.py[DEBUG]: Cloud-init v. ' '19.1-1-gbaa47854-0ubuntu1~18.04.1 running \'init-local\' ' 'at Mon, 08 Jul 2019 17:40:49 +0000. Up 18.84 seconds.') infh.close() outfh = open(log_path, 'w+') outfh.close() def set_up_dummy_file(self, path, log_path): infh = open(path, 'w+') infh.write('dummy data') infh.close() outfh = open(log_path, 'w+') outfh.close() def remove_dummy_file(self, path, log_path): if os.path.isfile(path): os.remove(path) if os.path.isfile(log_path): os.remove(log_path) @mock.patch('cloudinit.analyze.show.dist_check_timestamp', return_value=err_code) def test_boot_invalid_distro(self, m_dist_check_timestamp): path = os.path.dirname(os.path.abspath(__file__)) log_path = path + '/boot-test.log' path += '/dummy.log' self.set_up_dummy_file(path, log_path) parser = get_parser() args = parser.parse_args(args=['boot', '-i', path, '-o', log_path]) name_default = '' analyze_boot(name_default, args) # now args have been tested, go into outfile and make sure error # message is in the outfile outfh = open(args.outfile, 'r') data = outfh.read() err_string = 'Your Linux distro or container does not support this ' \ 'functionality.\nYou must be running a Kernel ' \ 'Telemetry supported distro.\nPlease check ' \ 'https://cloudinit.readthedocs.io/en/latest/topics' \ '/analyze.html for more information on supported ' \ 'distros.\n' self.remove_dummy_file(path, log_path) self.assertEqual(err_string, data) @mock.patch("cloudinit.util.is_container", return_value=True) @mock.patch('cloudinit.subp.subp', return_value=('U=1000000', None)) def test_container_no_ci_log_line(self, m_is_container, m_subp): path = os.path.dirname(os.path.abspath(__file__)) log_path = path + '/boot-test.log' path += '/dummy.log' self.set_up_dummy_file(path, log_path) parser = get_parser() args = parser.parse_args(args=['boot', '-i', path, '-o', log_path]) name_default = '' finish_code = analyze_boot(name_default, args) self.remove_dummy_file(path, log_path) self.assertEqual(FAIL_CODE, finish_code) @mock.patch("cloudinit.util.is_container", return_value=True) @mock.patch('cloudinit.subp.subp', return_value=('U=1000000', None)) @mock.patch('cloudinit.analyze.__main__._get_events', return_value=[{ 'name': 'init-local', 'description': 'starting search', 'timestamp': 100000}]) @mock.patch('cloudinit.analyze.show.dist_check_timestamp', return_value=(CONTAINER_CODE, 1, 1, 1)) def test_container_ci_log_line(self, m_is_container, m_subp, m_get, m_g): path = os.path.dirname(os.path.abspath(__file__)) log_path = path + '/boot-test.log' path += '/dummy.log' self.set_up_dummy_file_ci(path, log_path) parser = get_parser() args = parser.parse_args(args=['boot', '-i', path, '-o', log_path]) name_default = '' finish_code = analyze_boot(name_default, args) self.remove_dummy_file(path, log_path) self.assertEqual(CONTAINER_CODE, finish_code)