Пример #1
0
def _install_manpage(src_path, man_dir):
    """Install the given manual page for COT.

    Args:
      src_path (str): Path to manual page file.
      man_dir (str): Base directory where page should be installed.
    Returns:
      tuple: (page_previously_installed, page_updated)
    Raises:
      IOError: if installation fails under some circumstances
      OSError: if installation fails under other circumstances
    """
    # Which man section does this belong in?
    filename = os.path.basename(src_path)
    section = os.path.splitext(filename)[1][1:]
    dest = os.path.join(man_dir, "man{0}".format(section))
    Helper.mkdir(dest)

    previously_installed = False
    dest_path = os.path.join(dest, filename)
    if os.path.exists(dest_path):
        previously_installed = True
        if filecmp.cmp(src_path, dest_path):
            logger.verbose("File %s does not need to be updated", dest_path)
            return previously_installed, False

    Helper.copy_file(src_path, dest_path)
    return previously_installed, True
Пример #2
0
def _install_manpage(src_path, man_dir):
    """Install the given manual page for COT.

    Args:
      src_path (str): Path to manual page file.
      man_dir (str): Base directory where page should be installed.
    Returns:
      tuple: (page_previously_installed, page_updated)
    Raises:
      IOError: if installation fails under some circumstances
      OSError: if installation fails under other circumstances
    """
    # Which man section does this belong in?
    filename = os.path.basename(src_path)
    section = os.path.splitext(filename)[1][1:]
    dest = os.path.join(man_dir, "man{0}".format(section))
    Helper.mkdir(dest)

    previously_installed = False
    dest_path = os.path.join(dest, filename)
    if os.path.exists(dest_path):
        previously_installed = True
        if filecmp.cmp(src_path, dest_path):
            logger.verbose("File %s does not need to be updated", dest_path)
            return previously_installed, False

    Helper.copy_file(src_path, dest_path)
    return previously_installed, True
Пример #3
0
    def test_nondefault_permissions(self, mock_isdir, mock_exists,
                                    mock_makedirs, mock_check_call):
        """Non-default permissions should be applied whether sudo or not."""
        # Non-sudo case
        self.assertTrue(Helper.mkdir('/foo/bar', 511))  # 511 == 0o777
        mock_isdir.assert_called_with('/foo/bar')
        mock_exists.assert_called_with('/foo/bar')
        mock_makedirs.assert_called_with('/foo/bar', 511)
        mock_check_call.assert_not_called()

        # Sudo case
        mock_makedirs.reset_mock()
        mock_makedirs.side_effect = OSError
        self.assertTrue(Helper.mkdir('/foo/bar', 511))  # 511 == 0o777
        mock_makedirs.assert_called_with('/foo/bar', 511)
        mock_check_call.assert_called_with(
            ['sudo', 'mkdir', '-p', '--mode=777', '/foo/bar'])
Пример #4
0
 def test_permission_ok(self, mock_isdir, mock_exists,
                        mock_makedirs, mock_check_call):
     """Successfully create directory with user permissions."""
     self.assertTrue(Helper.mkdir('/foo/bar'))
     mock_isdir.assert_called_with('/foo/bar')
     mock_exists.assert_called_with('/foo/bar')
     mock_makedirs.assert_called_with('/foo/bar', 493)  # 493 == 0o755
     mock_check_call.assert_not_called()
Пример #5
0
    def test_nondefault_permissions(self, mock_isdir, mock_exists,
                                    mock_makedirs, mock_check_call):
        """Non-default permissions should be applied whether sudo or not."""
        # Non-sudo case
        self.assertTrue(Helper.mkdir('/foo/bar', 511))  # 511 == 0o777
        mock_isdir.assert_called_with('/foo/bar')
        mock_exists.assert_called_with('/foo/bar')
        mock_makedirs.assert_called_with('/foo/bar', 511)
        mock_check_call.assert_not_called()

        # Sudo case
        mock_makedirs.reset_mock()
        mock_makedirs.side_effect = OSError
        self.assertTrue(Helper.mkdir('/foo/bar', 511))  # 511 == 0o777
        mock_makedirs.assert_called_with('/foo/bar', 511)
        mock_check_call.assert_called_with(
            ['sudo', 'mkdir', '-p', '-m', '777', '/foo/bar'])
Пример #6
0
 def test_permission_ok(self, mock_isdir, mock_exists,
                        mock_makedirs, mock_check_call):
     """Successfully create directory with user permissions."""
     self.assertTrue(Helper.mkdir('/foo/bar'))
     mock_isdir.assert_called_with('/foo/bar')
     mock_exists.assert_called_with('/foo/bar')
     mock_makedirs.assert_called_with('/foo/bar', 493)  # 493 == 0o755
     mock_check_call.assert_not_called()
Пример #7
0
 def test_already_exists(self, mock_isdir, mock_exists,
                         mock_makedirs, mock_check_call):
     """Test case where the target directory already exists."""
     mock_isdir.return_value = True
     self.assertTrue(Helper.mkdir('/foo/bar'))
     mock_isdir.assert_called_with('/foo/bar')
     mock_exists.assert_not_called()
     mock_makedirs.assert_not_called()
     mock_check_call.assert_not_called()
Пример #8
0
 def test_already_exists(self, mock_isdir, mock_exists,
                         mock_makedirs, mock_check_call):
     """Test case where the target directory already exists."""
     mock_isdir.return_value = True
     self.assertTrue(Helper.mkdir('/foo/bar'))
     mock_isdir.assert_called_with('/foo/bar')
     mock_exists.assert_not_called()
     mock_makedirs.assert_not_called()
     mock_check_call.assert_not_called()
Пример #9
0
 def test_need_sudo(self, mock_isdir, mock_exists,
                    mock_makedirs, mock_check_call):
     """Directory creation needs sudo."""
     mock_makedirs.side_effect = OSError
     self.assertTrue(Helper.mkdir('/foo/bar'))
     mock_isdir.assert_called_with('/foo/bar')
     mock_exists.assert_called_with('/foo/bar')
     mock_makedirs.assert_called_with('/foo/bar', 493)  # 493 == 0o755
     mock_check_call.assert_called_with(
         ['sudo', 'mkdir', '-p', '--mode=755', '/foo/bar'])
Пример #10
0
 def test_need_sudo(self, mock_isdir, mock_exists,
                    mock_makedirs, mock_check_call):
     """Directory creation needs sudo."""
     mock_makedirs.side_effect = OSError
     self.assertTrue(Helper.mkdir('/foo/bar'))
     mock_isdir.assert_called_with('/foo/bar')
     mock_exists.assert_called_with('/foo/bar')
     mock_makedirs.assert_called_with('/foo/bar', 493)  # 493 == 0o755
     mock_check_call.assert_called_with(
         ['sudo', 'mkdir', '-p', '-m', '755', '/foo/bar'])
Пример #11
0
 def test_permission_ok(self, mock_copy, mock_check_call):
     """File copy succeeds with user permissions."""
     self.assertTrue(Helper.copy_file('/foo', '/bar'))
     mock_copy.assert_called_with('/foo', '/bar')
     mock_check_call.assert_not_called()
Пример #12
0
 def setUp(self):
     """Test case setup function called automatically prior to each test."""
     self.helper = Helper("generic")
     super(HelperGenericTest, self).setUp()
Пример #13
0
 def setUp(self):
     """Test case setup function called automatically prior to each test."""
     self.helper = Helper("generic")
     super(HelperGenericTest, self).setUp()
Пример #14
0
 def test_need_sudo(self, mock_copy, mock_check_call):
     """File copy needs sudo."""
     mock_copy.side_effect = OSError
     self.assertTrue(Helper.copy_file('/foo', '/bar'))
     mock_copy.assert_called_with('/foo', '/bar')
     mock_check_call.assert_called_with(['sudo', 'cp', '/foo', '/bar'])
Пример #15
0
 def test_permission_ok(self, mock_copy, mock_check_call):
     """File copy succeeds with user permissions."""
     self.assertTrue(Helper.copy_file('/foo', '/bar'))
     mock_copy.assert_called_with('/foo', '/bar')
     mock_check_call.assert_not_called()
Пример #16
0
 def test_need_sudo(self, mock_copy, mock_check_call):
     """File copy needs sudo."""
     mock_copy.side_effect = OSError
     self.assertTrue(Helper.copy_file('/foo', '/bar'))
     mock_copy.assert_called_with('/foo', '/bar')
     mock_check_call.assert_called_with(['sudo', 'cp', '/foo', '/bar'])
Пример #17
0
class HelperGenericTest(HelperTestCase):
    """Test cases for generic Helper class."""

    def setUp(self):
        """Test case setup function called automatically prior to each test."""
        self.helper = Helper("generic")
        super(HelperGenericTest, self).setUp()

    def tearDown(self):
        """Cleanup function called automatically prior to each test."""
        self.helper._installed = False
        Helper._provider_package = {}
        super(HelperGenericTest, self).tearDown()

    def test_check_call_helpernotfounderror(self):
        """HelperNotFoundError if executable doesn't exist."""
        self.assertRaises(HelperNotFoundError,
                          check_call, ["not_a_command"])
        self.assertRaises(HelperNotFoundError,
                          check_call,
                          ["not_a_command"], require_success=True)

    def test_check_call_helpererror(self):
        """HelperError if executable fails and require_success is set."""
        with self.assertRaises(HelperError) as catcher:
            check_call(["false"])
        self.assertEqual(catcher.exception.errno, 1)

        check_call(["false"], require_success=False)

    @mock.patch('subprocess.check_call')
    def test_check_call_permissions_needed(self, mock_check_call):
        """Test cases where sudo permission is needed."""
        def raise_oserror(args, **_):
            """Raise an OSError unless using 'sudo'."""
            if args[0] != 'sudo':
                raise OSError(13, 'permission denied')
            return
        mock_check_call.side_effect = raise_oserror

        # Without retry_on_sudo, we reraise the permissions error
        with self.assertRaises(OSError) as catcher:
            check_call(["false"])
        self.assertEqual(catcher.exception.errno, 13)
        mock_check_call.assert_called_once_with(["false"])

        # With retry_on_sudo, we retry.
        mock_check_call.reset_mock()
        check_call(["false"], retry_with_sudo=True)
        mock_check_call.assert_has_calls([
            mock.call(['false']),
            mock.call(['sudo', 'false']),
        ])

        # Now a variant - the subprocess call actually executed, but the
        # process exited with a non-zero exit code
        def raise_subprocess_error(args, **_):
            """Raise a CalledProcessError unless using 'sudo'."""
            if args[0] != 'sudo':
                raise subprocess.CalledProcessError(1, " ".join(args))
            return
        mock_check_call.reset_mock()
        mock_check_call.side_effect = raise_subprocess_error

        # Without retry_on_sudo, we reraise the permissions error
        with self.assertRaises(HelperError) as catcher:
            check_call(["false"])
        self.assertEqual(catcher.exception.errno, 1)
        mock_check_call.assert_called_once_with(["false"])

        # With retry_on_sudo, we retry.
        mock_check_call.reset_mock()
        check_call(["false"], retry_with_sudo=True)
        mock_check_call.assert_has_calls([
            mock.call(['false']),
            mock.call(['sudo', 'false']),
        ])

    def test_check_output_helpernotfounderror(self):
        """HelperNotFoundError if executable doesn't exist."""
        self.assertRaises(HelperNotFoundError,
                          check_output, ["not_a_command"])
        self.assertRaises(HelperNotFoundError,
                          check_output, ["not_a_command"],
                          require_success=True)

    def test_check_output_oserror(self):
        """OSError if requested command isn't an executable."""
        self.assertRaises(OSError,
                          check_output, self.input_ovf)

    def test_check_output_helpererror(self):
        """HelperError if executable fails and require_success is set."""
        with self.assertRaises(HelperError) as catcher:
            check_output(["false"])

        self.assertEqual(catcher.exception.errno, 1)

        check_output(["false"], require_success=False)

    @mock.patch('distutils.spawn.find_executable', return_value=None)
    def test_helper_not_found(self, *_):
        """Make sure helper.path is None if find_executable fails."""
        self.assertEqual(self.helper.path, None)

    @mock.patch('COT.helpers.Helper._install')
    def test_install_already_present(self, mock_install):
        """Make installation is not attempted unnecessarily."""
        self.helper._installed = True
        self.helper.install()
        mock_install.assert_not_called()

    @mock.patch('COT.helpers.Helper.installable',
                new_callable=mock.PropertyMock, return_value=True)
    def test_install_not_implemented(self, *_):
        """If installable lies, default _install method should fail cleanly."""
        self.helper._installed = False
        self.assertRaises(NotImplementedError, self.helper.install)

    @mock.patch('COT.helpers.Helper.installable',
                new_callable=mock.PropertyMock, return_value=True)
    @mock.patch('platform.system', return_value='Darwin')
    def test_install_missing_package_manager_mac(self, *_):
        """RuntimeError if Mac install supported but brew/port are absent."""
        self.helper._installed = False
        self.helper._provider_package['brew'] = 'install-me-with-brew'
        self.helper._provider_package['port'] = 'install-me-with-port'
        self.select_package_manager(None)
        with self.assertRaises(RuntimeError) as catcher:
            self.helper.install()
        msg = str(catcher.exception)
        self.assertRegex(msg, "Unsure how to install generic.")
        # Since both helpers are supported, we should see both messages
        self.assertRegex(msg, "COT can use Homebrew")
        self.assertRegex(msg, "COT can use MacPorts")

        del self.helper._provider_package['brew']
        with self.assertRaises(RuntimeError) as catcher:
            self.helper.install()
        msg = str(catcher.exception)
        self.assertRegex(msg, "Unsure how to install generic.")
        # Now we should only see the supported one
        self.assertNotRegex(msg, "COT can use Homebrew")
        self.assertRegex(msg, "COT can use MacPorts")

        del self.helper._provider_package['port']
        # Now we should fall back to NotImplementedError
        with self.assertRaises(NotImplementedError) as catcher:
            self.helper.install()
        msg = str(catcher.exception)
        self.assertRegex(msg, "Unsure how to install generic.")
        self.assertNotRegex(msg, "COT can use Homebrew")
        self.assertNotRegex(msg, "COT can use MacPorts")

        self.helper._provider_package['brew'] = 'install-me-with-brew'
        with self.assertRaises(RuntimeError) as catcher:
            self.helper.install()
        msg = str(catcher.exception)
        self.assertRegex(msg, "Unsure how to install generic.")
        # Now we should only see the supported one
        self.assertRegex(msg, "COT can use Homebrew")
        self.assertNotRegex(msg, "COT can use MacPorts")

    @mock.patch('COT.helpers.Helper._install')
    @mock.patch('COT.helpers.Helper.installable',
                new_callable=mock.PropertyMock, return_value=True)
    def test_install_bad_implementation(self, *_):
        """If custom _install() doesn't do its job, install() catches it."""
        self.assertRaises(HelperNotFoundError, self.helper.install)

    def test_call_install(self):
        """call will call install, which raises an error."""
        self.assertRaises(NotImplementedError,
                          self.helper.call, ["Hello!"])

    def test_call_no_install(self):
        """If not installed, and user declines, raise HelperNotFoundError."""
        _ui = Helper.USER_INTERFACE
        Helper.USER_INTERFACE = UI()
        Helper.USER_INTERFACE.default_confirm_response = False
        try:
            self.assertRaises(HelperNotFoundError,
                              self.helper.call, ["Hello!"])
        finally:
            Helper.USER_INTERFACE = _ui

    def test_download_and_expand_tgz(self):
        """Validate the download_and_expand_tgz() context_manager."""
        try:
            with self.helper.download_and_expand_tgz(
                "https://github.com/glennmatthews/cot/archive/master.tar.gz"
            ) as directory:
                self.assertTrue(os.path.exists(directory))
                self.assertTrue(os.path.exists(
                    os.path.join(directory, "cot-master")))
                self.assertTrue(os.path.exists(
                    os.path.join(directory, "cot-master", "COT")))
                self.assertTrue(os.path.exists(
                    os.path.join(directory, "cot-master", "COT", "tests")))
                self.assertTrue(os.path.exists(
                    os.path.join(directory, "cot-master", "COT", "tests",
                                 "ut.py")))
        except requests.exceptions.ConnectionError:
            # unable to connect to github - might be an isolated environment
            self.fail("ConnectionError when trying to download from GitHub")
        # Temporary directory should be cleaned up when done
        self.assertFalse(os.path.exists(directory))
Пример #18
0
class HelperGenericTest(HelperTestCase):
    """Test cases for generic Helper class."""

    def setUp(self):
        """Test case setup function called automatically prior to each test."""
        self.helper = Helper("generic")
        super(HelperGenericTest, self).setUp()

    def tearDown(self):
        """Cleanup function called automatically prior to each test."""
        self.helper._installed = False
        Helper._provider_package = {}
        super(HelperGenericTest, self).tearDown()

    def test_check_call_helpernotfounderror(self):
        """HelperNotFoundError if executable doesn't exist."""
        self.assertRaises(HelperNotFoundError,
                          check_call, ["not_a_command"])
        self.assertRaises(HelperNotFoundError,
                          check_call,
                          ["not_a_command"], require_success=True)

    def test_check_call_helpererror(self):
        """HelperError if executable fails and require_success is set."""
        with self.assertRaises(HelperError) as catcher:
            check_call(["false"])
        self.assertEqual(catcher.exception.errno, 1)

        check_call(["false"], require_success=False)

    @mock.patch('subprocess.check_call')
    def test_check_call_permissions_needed(self, mock_check_call):
        """Test cases where sudo permission is needed."""
        def raise_oserror(args, **_):
            """Raise an OSError unless using 'sudo'."""
            if args[0] != 'sudo':
                raise OSError(13, 'permission denied')
            return
        mock_check_call.side_effect = raise_oserror

        # Without retry_on_sudo, we reraise the permissions error
        with self.assertRaises(OSError) as catcher:
            check_call(["false"])
        self.assertEqual(catcher.exception.errno, 13)
        mock_check_call.assert_called_once_with(["false"])

        # With retry_on_sudo, we retry.
        mock_check_call.reset_mock()
        check_call(["false"], retry_with_sudo=True)
        mock_check_call.assert_has_calls([
            mock.call(['false']),
            mock.call(['sudo', 'false']),
        ])

        # Now a variant - the subprocess call actually executed, but the
        # process exited with a non-zero exit code
        def raise_subprocess_error(args, **_):
            """Raise a CalledProcessError unless using 'sudo'."""
            if args[0] != 'sudo':
                raise subprocess.CalledProcessError(1, " ".join(args))
            return
        mock_check_call.reset_mock()
        mock_check_call.side_effect = raise_subprocess_error

        # Without retry_on_sudo, we reraise the permissions error
        with self.assertRaises(HelperError) as catcher:
            check_call(["false"])
        self.assertEqual(catcher.exception.errno, 1)
        mock_check_call.assert_called_once_with(["false"])

        # With retry_on_sudo, we retry.
        mock_check_call.reset_mock()
        check_call(["false"], retry_with_sudo=True)
        mock_check_call.assert_has_calls([
            mock.call(['false']),
            mock.call(['sudo', 'false']),
        ])

    def test_check_output_helpernotfounderror(self):
        """HelperNotFoundError if executable doesn't exist."""
        self.assertRaises(HelperNotFoundError,
                          check_output, ["not_a_command"])
        self.assertRaises(HelperNotFoundError,
                          check_output, ["not_a_command"],
                          require_success=True)

    def test_check_output_oserror(self):
        """OSError if requested command isn't an executable."""
        self.assertRaises(OSError,
                          check_output, self.input_ovf)

    def test_check_output_helpererror(self):
        """HelperError if executable fails and require_success is set."""
        with self.assertRaises(HelperError) as catcher:
            check_output(["false"])

        self.assertEqual(catcher.exception.errno, 1)

        check_output(["false"], require_success=False)

    @mock.patch('distutils.spawn.find_executable', return_value=None)
    def test_helper_not_found(self, *_):
        """Make sure helper.path is None if find_executable fails."""
        self.assertEqual(self.helper.path, None)

    @mock.patch('COT.helpers.Helper._install')
    def test_install_already_present(self, mock_install):
        """Make installation is not attempted unnecessarily."""
        self.helper._installed = True
        self.helper.install()
        mock_install.assert_not_called()

    @mock.patch('COT.helpers.Helper.installable',
                new_callable=mock.PropertyMock, return_value=True)
    def test_install_not_implemented(self, *_):
        """If installable lies, default _install method should fail cleanly."""
        self.helper._installed = False
        self.assertRaises(NotImplementedError, self.helper.install)

    @mock.patch('COT.helpers.Helper.installable',
                new_callable=mock.PropertyMock, return_value=True)
    @mock.patch('platform.system', return_value='Darwin')
    def test_install_missing_package_manager_mac(self, *_):
        """RuntimeError if Mac install supported but brew/port are absent."""
        self.helper._installed = False
        self.helper._provider_package['brew'] = 'install-me-with-brew'
        self.helper._provider_package['port'] = 'install-me-with-port'
        self.select_package_manager(None)
        with self.assertRaises(RuntimeError) as catcher:
            self.helper.install()
        msg = str(catcher.exception)
        self.assertRegex(msg, "Unsure how to install generic.")
        # Since both helpers are supported, we should see both messages
        self.assertRegex(msg, "COT can use Homebrew")
        self.assertRegex(msg, "COT can use MacPorts")

        del self.helper._provider_package['brew']
        with self.assertRaises(RuntimeError) as catcher:
            self.helper.install()
        msg = str(catcher.exception)
        self.assertRegex(msg, "Unsure how to install generic.")
        # Now we should only see the supported one
        self.assertNotRegex(msg, "COT can use Homebrew")
        self.assertRegex(msg, "COT can use MacPorts")

        del self.helper._provider_package['port']
        # Now we should fall back to NotImplementedError
        with self.assertRaises(NotImplementedError) as catcher:
            self.helper.install()
        msg = str(catcher.exception)
        self.assertRegex(msg, "Unsure how to install generic.")
        self.assertNotRegex(msg, "COT can use Homebrew")
        self.assertNotRegex(msg, "COT can use MacPorts")

        self.helper._provider_package['brew'] = 'install-me-with-brew'
        with self.assertRaises(RuntimeError) as catcher:
            self.helper.install()
        msg = str(catcher.exception)
        self.assertRegex(msg, "Unsure how to install generic.")
        # Now we should only see the supported one
        self.assertRegex(msg, "COT can use Homebrew")
        self.assertNotRegex(msg, "COT can use MacPorts")

    @mock.patch('COT.helpers.Helper._install')
    @mock.patch('COT.helpers.Helper.installable',
                new_callable=mock.PropertyMock, return_value=True)
    def test_install_bad_implementation(self, *_):
        """If custom _install() doesn't do its job, install() catches it."""
        self.assertRaises(HelperNotFoundError, self.helper.install)

    def test_call_install(self):
        """call will call install, which raises an error."""
        self.assertRaises(NotImplementedError,
                          self.helper.call, ["Hello!"])

    def test_call_no_install(self):
        """If not installed, and user declines, raise HelperNotFoundError."""
        _ui = Helper.USER_INTERFACE
        Helper.USER_INTERFACE = UI()
        Helper.USER_INTERFACE.default_confirm_response = False
        try:
            self.assertRaises(HelperNotFoundError,
                              self.helper.call, ["Hello!"])
        finally:
            Helper.USER_INTERFACE = _ui

    def test_download_and_expand_tgz(self):
        """Validate the download_and_expand_tgz() context_manager."""
        try:
            with self.helper.download_and_expand_tgz(
                "https://github.com/glennmatthews/cot/archive/master.tar.gz"
            ) as directory:
                self.assertTrue(os.path.exists(directory))
                self.assertTrue(os.path.exists(
                    os.path.join(directory, "cot-master")))
                self.assertTrue(os.path.exists(
                    os.path.join(directory, "cot-master", "COT")))
                self.assertTrue(os.path.exists(
                    os.path.join(directory, "cot-master", "COT", "tests")))
                self.assertTrue(os.path.exists(
                    os.path.join(directory, "cot-master", "COT", "tests",
                                 "cot_testcase.py")))
        except requests.exceptions.ConnectionError:
            # unable to connect to github - might be an isolated environment
            self.fail("ConnectionError when trying to download from GitHub")
        # Temporary directory should be cleaned up when done
        self.assertFalse(os.path.exists(directory))