#!/usr/bin/python3 import grp import io import os import pwd from test.support import EnvironmentVarGuard, run_unittest import unittest # These tests require Mock 0.7.0 import mock from ubiquity import misc _proc_swaps = [ 'Filename\t\t\t\tType\t\tSize\tUsed\tPriority', '/dev/sda5 partition\t1046524\t56160\t-1'] _disk_info = ('Ubuntu-Server 10.04.1 LTS _Lucid Lynx_ ' '- Release i386 (20100816.2)') _proc_mounts = [ 'rootfs / rootfs rw 0 0', 'none /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0', 'none /proc proc rw,nosuid,nodev,noexec,relatime 0 0', ('none /dev devtmpfs ' 'rw,relatime,size=503688k,nr_inodes=125922,mode=755 0 0'), ('none /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,' 'ptmxmode=000 0 0'), 'fusectl /sys/fs/fuse/connections fusectl rw,relatime 0 0', ('/dev/disk/by-uuid/35583897-668f-4303-80a1-aa4e7f599978 / ext4 ' 'rw,relatime,errors=remount-ro,barrier=1,data=ordered 0 0'), 'none /sys/kernel/debug debugfs rw,relatime 0 0', 'none /sys/kernel/security securityfs rw,relatime 0 0', 'none /dev/shm tmpfs rw,nosuid,nodev,relatime 0 0', 'none /var/run tmpfs rw,nosuid,relatime,mode=755 0 0', 'none /var/lock tmpfs rw,nosuid,nodev,noexec,relatime 0 0', ('binfmt_misc /proc/sys/fs/binfmt_misc binfmt_misc ' 'rw,nosuid,nodev,noexec,relatime 0 0'), ('gvfs-fuse-daemon /home/evan/.gvfs fuse.gvfs-fuse-daemon ' 'rw,nosuid,nodev,relatime,user_id=1000,group_id=1000 0 0'), ] class EnvironmentVarGuardRestore(EnvironmentVarGuard): """Stronger version of EnvironmentVarGuard. This class restores os.environ even if something within its context manipulates os.environ directly. """ def __init__(self): EnvironmentVarGuard.__init__(self) self._environ = self._environ.copy() class MiscTests(unittest.TestCase): def setUp(self): misc.get_release.release_info = None @mock.patch('builtins.open') def test_is_swap(self, mock_open): magic = mock.MagicMock(spec=io.TextIOBase) mock_open.return_value = magic magic.__enter__.return_value = magic magic.__iter__.return_value = iter(_proc_swaps) self.assertTrue(misc.is_swap('/dev/sda5')) self.assertFalse(misc.is_swap('/dev/sda')) @mock.patch('builtins.open') def test_is_swap_fail(self, mock_open): mock_open.side_effect = Exception('Ka-blamo!') self.assertFalse(misc.is_swap('/dev/sda5')) def test_format_size(self): self.assertEqual(misc.format_size(4 * 1000 ** 0), '4.0 B') self.assertEqual(misc.format_size(4 * 1000 ** 1), '4.0 kB') self.assertEqual(misc.format_size(4 * 1000 ** 2), '4.0 MB') self.assertEqual(misc.format_size(4 * 1000 ** 3), '4.0 GB') self.assertEqual(misc.format_size(4 * 1000 ** 4), '4.0 TB') def test_create_bool(self): self.assertIs(misc.create_bool('true'), True) self.assertIs(misc.create_bool('false'), False) # debconf will only ever return 'true' or 'false', though arguably # this particular behavior of returning back the parameter will bite # us at some point. self.assertIs(misc.create_bool('True'), 'True') def test_get_install_medium(self): # TODO: Need to patch out os.access and the internals of # raise_privileges. If the uid is not set to 0 inside our mocked # os.access, raise an exception as a side effect. pass @mock.patch('builtins.open') def test_get_release(self, mock_open): magic = mock.MagicMock(spec=io.TextIOBase) magic.__enter__.return_value = magic mock_open.return_value = magic magic.readline.return_value = _disk_info release = misc.get_release() self.assertEqual(release.name, 'Ubuntu Server') self.assertEqual(release.version, '10.04.1 LTS') @mock.patch('builtins.open') def test_get_release_fail(self, mock_open): mock_open.side_effect = Exception('Pow!') release = misc.get_release() self.assertEqual(release.name, 'Ubuntu') self.assertEqual(release.version, '') # @mock.patch('os.path.exists') # def windows_startup_folder(self, mock_exists): # #mock_exists.return_value = True # locations = [ # # Windows 7 # 'ProgramData/Microsoft/Windows/Start Menu/Programs/Startup', # # Windows XP # 'Documents and Settings/All Users/Start Menu/Programs/Startup', # # Windows NT # 'Winnt/Profiles/All Users/Start Menu/Programs/Startup', # ] # locations_iter = iter(locations) # def exists(path): # return path == locations_iter.next() # self.assertEqual(misc.windows_startup_folder('/tmp/tmp.XXXXXX')) @mock.patch('builtins.open') def test_mount_info(self, mock_open): magic = mock.MagicMock(spec=io.TextIOBase) magic.__enter__.return_value = magic mock_open.return_value = magic # TODO come up with better mountpoints. magic.__iter__.return_value = iter(_proc_mounts) release = misc.mount_info('/dev/pts') self.assertEqual(release, ('none', 'devpts', 'rw')) magic.__iter__.return_value = iter(_proc_mounts) release = misc.mount_info('/proc') self.assertEqual(release, ('none', 'proc', 'rw')) magic.__iter__.return_value = iter(_proc_mounts) release = misc.mount_info('XXX') self.assertEqual(release, ('', '', '')) def test_debconf_escape(self): self.assertEqual(misc.debconf_escape('\\A test string\n'), '\\\\A\\ test\\ string\\n') @mock.patch('ubiquity.gsettings.set_list') @mock.patch('ubiquity.misc.execute') def test_set_indicator_keymaps_english(self, mock_execute, mock_set_list): misc.set_indicator_keymaps('en') self.assertEqual(mock_execute.call_count, 1) self.assertEqual(mock_execute.call_args[0][0], 'setxkbmap') self.assertEqual(mock_set_list.call_count, 1) self.assertEqual( mock_set_list.call_args[0][0], 'org.gnome.libgnomekbd.keyboard') self.assertEqual(mock_set_list.call_args[0][1], 'layouts') self.assertEqual('us', mock_set_list.call_args[0][2][0]) self.assertEqual(len(mock_set_list.call_args[0][2]), 4) @mock.patch('ubiquity.gsettings.set_list') @mock.patch('ubiquity.misc.execute') def test_set_indicator_keymaps_french(self, mock_execute, mock_set_list): misc.set_indicator_keymaps('fr') self.assertEqual(mock_execute.call_count, 1) self.assertEqual(mock_execute.call_args[0][0], 'setxkbmap') self.assertEqual(mock_set_list.call_count, 1) self.assertEqual( mock_set_list.call_args[0][0], 'org.gnome.libgnomekbd.keyboard') self.assertEqual(mock_set_list.call_args[0][1], 'layouts') self.assertEqual('fr\toss', mock_set_list.call_args[0][2][0]) self.assertEqual(len(mock_set_list.call_args[0][2]), 4) @mock.patch('ubiquity.gsettings.set_list') @mock.patch('ubiquity.misc.execute') def test_set_indicator_keymaps_variants(self, mock_execute, mock_set_list): misc.set_indicator_keymaps('sv') self.assertEqual(mock_execute.call_count, 1) self.assertEqual(mock_execute.call_args[0][0], 'setxkbmap') self.assertEqual(mock_set_list.call_count, 1) self.assertEqual( mock_set_list.call_args[0][0], 'org.gnome.libgnomekbd.keyboard') self.assertEqual(mock_set_list.call_args[0][1], 'layouts') self.assertIn('se\tdvorak', mock_set_list.call_args[0][2]) @mock.patch('ubiquity.gsettings.set_list') @mock.patch('ubiquity.misc.execute') def test_set_indicator_keymaps_simplified_chinese(self, mock_execute, mock_set_list): misc.set_indicator_keymaps('zh_CN') self.assertEqual(mock_execute.call_count, 1) self.assertEqual(mock_execute.call_args[0][0], 'setxkbmap') self.assertEqual(mock_set_list.call_count, 1) self.assertEqual( mock_set_list.call_args[0][0], 'org.gnome.libgnomekbd.keyboard') self.assertEqual(mock_set_list.call_args[0][1], 'layouts') self.assertEqual('cn', mock_set_list.call_args[0][2][0]) self.assertEqual(len(mock_set_list.call_args[0][2]), 1) @mock.patch('ubiquity.gsettings.set_list') @mock.patch('ubiquity.misc.execute') def test_set_indicator_keymaps_unknown(self, mock_execute, mock_set_list): misc.set_indicator_keymaps('unknownlanguage') self.assertEqual(mock_execute.call_count, 0) self.assertEqual(mock_set_list.call_count, 0) # class PartedServerTests(unittest.TestCase): # def setUp(self): # patcher = mock.patch('ubiquity.parted_server.PartedServer') # patcher.start() # # Probably best to patch at the dialog level rather than each method # # call. # # Maybe implement this once we have tests for PartedServer itself, # # with mocks we can reuse. # self.addCleanup(patcher.stop) # # def test_boot_device(self): # print misc.boot_device() class PrivilegeTests(unittest.TestCase): def setUp(self): # *whistles* for obj in ('os.geteuid', 'os.getuid', 'pwd.getpwuid', 'grp.getgrall', 'os.setgroups'): patcher = mock.patch(obj) patcher.start() self.addCleanup(patcher.stop) os.geteuid.return_value = 0 os.getuid.return_value = 0 pwd.getpwuid.return_value.pw_name = 'fakegrp' pwd.getpwuid.return_value.pw_gid = '1000' gr = mock.Mock() gr.gr_mem = ['fakegrp'] gr.gr_gid = 1234 grp.getgrall.return_value = [gr] def tearDown(self): # Reset the multiple call guard. misc._dropped_privileges = 0 @mock.patch('os.setegid') @mock.patch('os.seteuid') @mock.patch('os.setgroups') def test_drop_privileges(self, *args): with EnvironmentVarGuard() as env: env['PKEXEC_UID'] = '1000' misc.drop_privileges() os.seteuid.assert_called_once_with(1000) os.setegid.assert_called_once_with(1000) os.setgroups.assert_called_once_with([1234]) @mock.patch('os.seteuid') @mock.patch('os.setegid') @mock.patch('os.setgroups') def test_regain_privileges(self, *args): self.test_drop_privileges() misc.regain_privileges() os.seteuid.assert_called_once_with(0) os.setegid.assert_called_once_with(0) os.setgroups.assert_called_once_with([]) @mock.patch('os.setregid') @mock.patch('os.setreuid') def test_drop_all_privileges(self, *args): pwd.getpwuid.return_value.pw_dir = 'fakeusr' with EnvironmentVarGuardRestore(): os.environ['PKEXEC_UID'] = '1000' misc.drop_all_privileges() os.setreuid.assert_called_once_with(1000, 1000) os.setregid.assert_called_once_with(1000, 1000) os.setgroups.assert_called_once_with([1234]) self.assertEqual(os.environ['HOME'], 'fakeusr') class GrubDefaultTests(unittest.TestCase): """Support for testing ubiquity.misc.grub_default. This class mocks several methods to make it possible to test ubiquity.misc.grub_default. Individual tests should set self.devices to a list of elements as follows: [grub_dev, os_dev, by_id_dev] grub_dev should not be surrounded with (); os_dev should not be prefixed with /dev/; by_id_dev should not be prefixed with /dev/disk/by-id/. For example: [ ['hd0', 'sda', 'serial-number-for-sda'], ['hd1', 'sdb', 'serial-number-for-sdb'], ] Tests should also set self.cdrom_mount to a (disk, fs_type) pair, e.g. ('/dev/sr0', 'iso9660'), may set self.removable_devices to a list of paths to removable devices, e.g. ['/dev/sdb'], and may set self.boot_device to the path to a device containing /boot, e.g. '/dev/sdb'. """ def setUp(self): to_patch = ( 'os.path.realpath', 'os.path.samefile', 'ubiquity.misc.boot_device', 'ubiquity.misc.cdrom_mount_info', 'ubiquity.misc.grub_device_map', 'ubiquity.misc.is_removable', ) for obj in to_patch: patcher = mock.patch(obj) patcher.start() self.addCleanup(patcher.stop) os.path.realpath.side_effect = self.realpath_side_effect os.path.samefile.side_effect = self.samefile_side_effect misc.boot_device.side_effect = self.boot_device_side_effect misc.cdrom_mount_info.side_effect = self.cdrom_mount_info_side_effect misc.grub_device_map.side_effect = self.grub_device_map_side_effect misc.is_removable.side_effect = self.is_removable_side_effect self.removable_devices = [] self.boot_device = None def iter_devices(self): """Iterate through devices, expanding abbreviated forms.""" for grub_dev, os_dev, by_id_dev in self.devices: yield ('(%s)' % grub_dev, '/dev/%s' % os_dev, '/dev/disk/by-id/%s' % by_id_dev) def realpath_side_effect(self, filename): filename = os.path.abspath(filename) for _, os_dev, by_id_dev in self.iter_devices(): if filename in (os_dev, by_id_dev): return os_dev return filename def samefile_side_effect(self, f1, f2): f1 = os.path.abspath(f1) f2 = os.path.abspath(f2) if f1 == f2: return True for _, os_dev, by_id_dev in self.iter_devices(): if f1 == os_dev and f2 == by_id_dev: return True elif f1 == by_id_dev and f2 == os_dev: return True return False def boot_device_side_effect(self): return self.boot_device def cdrom_mount_info_side_effect(self): return list(self.cdrom_mount) def grub_device_map_side_effect(self): device_map = [] for grub_dev, _, by_id_dev in self.iter_devices(): device_map.append('%s\t%s' % (grub_dev, by_id_dev)) return device_map def is_removable_side_effect(self, device): if device in self.removable_devices: return device else: return None def test_removable(self): self.devices = [['hd0', 'sda', 'serial-number-for-sda']] self.cdrom_mount = ('/dev/sr0', 'iso9660') self.boot_device = '/dev/sdb' self.removable_devices = [self.boot_device] self.assertEqual('/dev/sdb', misc.grub_default()) def test_use_first_disk(self): self.devices = [ ['hd0', 'sda', 'disk-1'], ['hd1', 'sdb', 'disk-2'], ] self.cdrom_mount = ('/dev/sr0', 'vfat') self.assertEqual('/dev/sda', misc.grub_default()) @mock.patch('ubiquity.misc.drop_privileges') @mock.patch('ubiquity.misc.regain_privileges') def test_avoid_cdrom(self, *args): self.devices = [ ['hd0', 'sda', 'cdrom'], ['hd1', 'sdb', 'disk'], ] self.cdrom_mount = ('/dev/sda', 'vfat') self.assertEqual('/dev/sdb', misc.grub_default()) self.cdrom_mount = ('/dev/disk/by-id/cdrom', 'vfat') self.assertEqual('/dev/sdb', misc.grub_default()) def test_usb_iso9660(self): self.devices = [ ['hd0', 'sda', 'usb'], ['hd1', 'sdb', 'disk'], ] self.cdrom_mount = ('/dev/sda', 'iso9660') self.removable_devices = ['/dev/sda'] self.boot_device = None self.assertEqual('/dev/sdb', misc.grub_default()) self.boot_device = '/dev/sdb' self.assertEqual('/dev/sdb', misc.grub_default()) self.devices = [ ['hd0', 'sda', 'disk'], ['hd1', 'sdb', 'usb'], ] self.cdrom_mount = ('/dev/sdb', 'iso9660') self.removable_devices = ['/dev/sdb'] self.boot_device = None self.assertEqual('/dev/sda', misc.grub_default()) self.boot_device = '/dev/sda' self.assertEqual('/dev/sda', misc.grub_default()) if __name__ == '__main__': run_unittest(MiscTests, PrivilegeTests, GrubDefaultTests)