Exemplo n.º 1
0
    def test_valid_services(
        self,
        m_is_config_value,
        show_all_names,
        allow_beta,
        is_beta,
        FakeConfig,
    ):
        m_is_config_value.return_value = allow_beta

        m_cls_1 = mock.MagicMock()
        m_inst_1 = mock.MagicMock()
        m_cls_1.is_beta = False
        m_inst_1.presentation_name = "ent1"
        m_inst_1.valid_names = ["ent1", "othername"]
        m_cls_1.return_value = m_inst_1

        m_cls_2 = mock.MagicMock()
        m_inst_2 = mock.MagicMock()
        m_cls_2.is_beta = is_beta
        m_inst_2.presentation_name = "ent2"
        m_inst_2.valid_names = ["ent2"]
        m_cls_2.return_value = m_inst_2

        ents = {m_cls_1, m_cls_2}

        with mock.patch.object(entitlements, "ENTITLEMENT_CLASSES", ents):
            expected_services = ["ent1"]
            if allow_beta or not is_beta:
                expected_services.append("ent2")
            if show_all_names:
                expected_services.append("othername")

            assert expected_services == entitlements.valid_services(
                cfg=FakeConfig(), all_names=show_all_names
            )
import textwrap

import mock
import pytest

from uaclient import config, entitlements, event_logger, exceptions, messages
from uaclient.cli import action_disable, main, main_error_handler
from uaclient.entitlements.entitlement_status import (
    CanDisableFailure,
    CanDisableFailureReason,
)

ALL_SERVICE_MSG = "\n".join(
    textwrap.wrap(
        "Try " + ", ".join(
            entitlements.valid_services(cfg=config.UAConfig(),
                                        allow_beta=True)) + ".",
        width=80,
        break_long_words=False,
        break_on_hyphens=False,
    ))

HELP_OUTPUT = textwrap.dedent("""\
usage: ua disable <service> [<service>] [flags]

Disable an Ubuntu Advantage service.

Arguments:
  service              the name(s) of the Ubuntu Advantage services to disable
                       One of: cc-eal, cis, esm-infra, fips, fips-updates,
                       livepatch
Exemplo n.º 3
0
    def test_invalid_service_names(
        self,
        _m_request_updated_contract,
        m_getuid,
        service,
        beta,
        event,
        FakeConfig,
    ):
        m_getuid.return_value = 0
        expected_error_tmpl = messages.INVALID_SERVICE_OP_FAILURE
        expected_msg = "One moment, checking your subscription first\n"

        cfg = FakeConfig.for_attached_machine()
        args_mock = mock.MagicMock()
        args_mock.service = service
        args_mock.beta = beta

        with pytest.raises(exceptions.UserFacingError) as err:
            fake_stdout = io.StringIO()
            with contextlib.redirect_stdout(fake_stdout):
                action_enable(args_mock, cfg)

        assert expected_msg == fake_stdout.getvalue()

        service_names = entitlements.valid_services(cfg=cfg, allow_beta=beta)
        ent_str = "Try " + ", ".join(service_names) + "."
        service_msg = "\n".join(
            textwrap.wrap(
                ent_str,
                width=80,
                break_long_words=False,
                break_on_hyphens=False,
            )
        )
        expected_error = expected_error_tmpl.format(
            operation="enable",
            invalid_service=", ".join(sorted(service)),
            service_msg=service_msg,
        )
        assert expected_error.msg == err.value.msg

        with pytest.raises(SystemExit):
            with mock.patch.object(
                event, "_event_logger_mode", event_logger.EventLoggerMode.JSON
            ):
                fake_stdout = io.StringIO()
                with contextlib.redirect_stdout(fake_stdout):
                    main_error_handler(action_enable)(args_mock, cfg)

        expected = {
            "_schema_version": event_logger.JSON_SCHEMA_VERSION,
            "result": "failure",
            "errors": [
                {
                    "message": expected_error.msg,
                    "message_code": expected_error.name,
                    "service": None,
                    "type": "system",
                }
            ],
            "failed_services": service,
            "needs_reboot": False,
            "processed_services": [],
            "warnings": [],
        }
        assert expected == json.loads(fake_stdout.getvalue())
Exemplo n.º 4
0
    def test_entitlements_not_found_and_beta(
        self,
        m_valid_services,
        m_entitlement_factory,
        _m_get_available_resources,
        _m_request_updated_contract,
        m_getuid,
        beta_flag,
        event,
        FakeConfig,
    ):
        m_getuid.return_value = 0
        expected_error_tmpl = messages.INVALID_SERVICE_OP_FAILURE

        m_ent1_cls = mock.Mock()
        m_ent1_obj = m_ent1_cls.return_value
        m_ent1_obj.enable.return_value = (False, None)

        m_ent2_cls = mock.Mock()
        m_ent2_cls.name = "ent2"
        m_ent2_is_beta = mock.PropertyMock(return_value=True)
        type(m_ent2_cls)._is_beta = m_ent2_is_beta
        m_ent2_obj = m_ent2_cls.return_value
        failure_reason = CanEnableFailure(CanEnableFailureReason.IS_BETA)
        if beta_flag:
            m_ent2_obj.enable.return_value = (True, None)
        else:
            m_ent2_obj.enable.return_value = (False, failure_reason)

        m_ent3_cls = mock.Mock()
        m_ent3_cls.name = "ent3"
        m_ent3_is_beta = mock.PropertyMock(return_value=False)
        type(m_ent3_cls)._is_beta = m_ent3_is_beta
        m_ent3_obj = m_ent3_cls.return_value
        m_ent3_obj.enable.return_value = (True, None)

        cfg = FakeConfig.for_attached_machine()
        assume_yes = False
        args_mock = mock.Mock()
        args_mock.service = ["ent1", "ent2", "ent3"]
        args_mock.assume_yes = assume_yes
        args_mock.beta = beta_flag

        def factory_side_effect(cfg, name, not_found_okay=True):
            if name == "ent2":
                return m_ent2_cls
            if name == "ent3":
                return m_ent3_cls
            return None

        m_entitlement_factory.side_effect = factory_side_effect

        def valid_services_side_effect(cfg, allow_beta, all_names=False):
            if allow_beta:
                return ["ent2", "ent3"]
            return ["ent2"]

        m_valid_services.side_effect = valid_services_side_effect

        expected_msg = "One moment, checking your subscription first\n"
        not_found_name = "ent1"
        mock_ent_list = [m_ent3_cls]
        mock_obj_list = [m_ent3_obj]

        service_names = entitlements.valid_services(cfg, allow_beta=beta_flag)
        ent_str = "Try " + ", ".join(service_names) + "."
        if not beta_flag:
            not_found_name += ", ent2"
        else:
            mock_ent_list.append(m_ent2_cls)
            mock_obj_list.append(m_ent3_obj)
        service_msg = "\n".join(
            textwrap.wrap(
                ent_str,
                width=80,
                break_long_words=False,
                break_on_hyphens=False,
            )
        )

        with pytest.raises(exceptions.UserFacingError) as err:
            fake_stdout = io.StringIO()
            with contextlib.redirect_stdout(fake_stdout):
                action_enable(args_mock, cfg)

        expected_error = expected_error_tmpl.format(
            operation="enable",
            invalid_service=not_found_name,
            service_msg=service_msg,
        )
        assert expected_error.msg == err.value.msg
        assert expected_msg == fake_stdout.getvalue()

        for m_ent_cls in mock_ent_list:
            assert [
                mock.call(
                    cfg,
                    assume_yes=assume_yes,
                    allow_beta=beta_flag,
                    called_name=m_ent_cls.name,
                )
            ] == m_ent_cls.call_args_list

        expected_enable_call = mock.call()
        for m_ent in mock_obj_list:
            assert [expected_enable_call] == m_ent.enable.call_args_list

        assert 0 == m_ent1_obj.call_count

        event.reset()
        with pytest.raises(SystemExit):
            with mock.patch.object(
                event, "_event_logger_mode", event_logger.EventLoggerMode.JSON
            ):
                fake_stdout = io.StringIO()
                with contextlib.redirect_stdout(fake_stdout):
                    main_error_handler(action_enable)(args_mock, cfg=cfg)

        expected_failed_services = ["ent1", "ent2"]
        if beta_flag:
            expected_failed_services = ["ent1"]

        expected = {
            "_schema_version": event_logger.JSON_SCHEMA_VERSION,
            "result": "failure",
            "errors": [
                {
                    "message": expected_error.msg,
                    "message_code": expected_error.name,
                    "service": None,
                    "type": "system",
                }
            ],
            "failed_services": expected_failed_services,
            "needs_reboot": False,
            "processed_services": ["ent2", "ent3"] if beta_flag else ["ent3"],
            "warnings": [],
        }
        assert expected == json.loads(fake_stdout.getvalue())
Exemplo n.º 5
0
    def test_entitlements_not_found_disabled_and_enabled(
        self,
        m_valid_services,
        m_entitlement_factory,
        _m_get_available_resources,
        _m_request_updated_contract,
        m_getuid,
        event,
        FakeConfig,
    ):
        m_getuid.return_value = 0
        expected_error_tmpl = messages.INVALID_SERVICE_OP_FAILURE

        m_ent1_cls = mock.Mock()
        m_ent1_obj = m_ent1_cls.return_value
        m_ent1_obj.enable.return_value = (False, None)

        m_ent2_cls = mock.Mock()
        m_ent2_cls.name = "ent2"
        m_ent2_is_beta = mock.PropertyMock(return_value=True)
        type(m_ent2_cls).is_beta = m_ent2_is_beta
        m_ent2_obj = m_ent2_cls.return_value
        m_ent2_obj.enable.return_value = (
            False,
            CanEnableFailure(CanEnableFailureReason.IS_BETA),
        )

        m_ent3_cls = mock.Mock()
        m_ent3_cls.name = "ent3"
        m_ent3_is_beta = mock.PropertyMock(return_value=False)
        type(m_ent3_cls).is_beta = m_ent3_is_beta
        m_ent3_obj = m_ent3_cls.return_value
        m_ent3_obj.enable.return_value = (True, None)

        def factory_side_effect(cfg, name, not_found_okay=True):
            if name == "ent2":
                return m_ent2_cls
            if name == "ent3":
                return m_ent3_cls
            return None

        m_entitlement_factory.side_effect = factory_side_effect
        m_valid_services.return_value = ["ent2", "ent3"]

        cfg = FakeConfig.for_attached_machine()
        assume_yes = False
        args_mock = mock.Mock()
        args_mock.service = ["ent1", "ent2", "ent3"]
        args_mock.assume_yes = assume_yes
        args_mock.beta = False

        expected_msg = "One moment, checking your subscription first\n"

        with pytest.raises(exceptions.UserFacingError) as err:
            fake_stdout = io.StringIO()
            with contextlib.redirect_stdout(fake_stdout):
                action_enable(args_mock, cfg)

        expected_error = expected_error_tmpl.format(
            operation="enable",
            invalid_service="ent1, ent2",
            service_msg=(
                "Try "
                + ", ".join(entitlements.valid_services(allow_beta=False))
                + "."
            ),
        )
        assert expected_error.msg == err.value.msg
        assert expected_msg == fake_stdout.getvalue()

        for m_ent_cls in [m_ent2_cls, m_ent3_cls]:
            assert [
                mock.call(
                    cfg,
                    assume_yes=assume_yes,
                    allow_beta=False,
                    called_name=m_ent_cls.name,
                )
            ] == m_ent_cls.call_args_list

        expected_enable_call = mock.call()
        for m_ent in [m_ent2_obj, m_ent3_obj]:
            assert [expected_enable_call] == m_ent.enable.call_args_list

        assert 0 == m_ent1_obj.call_count

        event.reset()
        with pytest.raises(SystemExit):
            with mock.patch.object(
                event, "_event_logger_mode", event_logger.EventLoggerMode.JSON
            ):
                fake_stdout = io.StringIO()
                with contextlib.redirect_stdout(fake_stdout):
                    main_error_handler(action_enable)(args_mock, cfg)

        expected = {
            "_schema_version": event_logger.JSON_SCHEMA_VERSION,
            "result": "failure",
            "errors": [
                {
                    "message": expected_error.msg,
                    "message_code": expected_error.name,
                    "service": None,
                    "type": "system",
                }
            ],
            "failed_services": ["ent1", "ent2"],
            "needs_reboot": False,
            "processed_services": ["ent3"],
            "warnings": [],
        }
        assert expected == json.loads(fake_stdout.getvalue())
Exemplo n.º 6
0
    def test_invalid_service_error_message(
        self,
        _request_updated_contract,
        m_getuid,
        uid,
        expected_error_template,
        is_attached,
        event,
        FakeConfig,
    ):
        """Check invalid service name results in custom error message."""

        m_getuid.return_value = uid
        if is_attached:
            cfg = FakeConfig.for_attached_machine()
            service_msg = "\n".join(
                textwrap.wrap(
                    (
                        "Try "
                        + ", ".join(
                            entitlements.valid_services(
                                cfg=cfg, allow_beta=True
                            )
                        )
                        + "."
                    ),
                    width=80,
                    break_long_words=False,
                    break_on_hyphens=False,
                )
            )
        else:
            cfg = FakeConfig()
            service_msg = "See https://ubuntu.com/advantage"

        args = mock.MagicMock()
        args.service = ["bogus"]
        args.command = "enable"
        with pytest.raises(exceptions.UserFacingError) as err:
            action_enable(args, cfg)

        if not uid:
            expected_error = expected_error_template.format(
                operation="enable",
                invalid_service="bogus",
                service_msg=service_msg,
            )
        else:
            expected_error = expected_error_template

        assert expected_error.msg == err.value.msg

        with pytest.raises(SystemExit):
            with mock.patch.object(
                event, "_event_logger_mode", event_logger.EventLoggerMode.JSON
            ):
                fake_stdout = io.StringIO()
                with contextlib.redirect_stdout(fake_stdout):
                    main_error_handler(action_enable)(args, cfg)

        expected = {
            "_schema_version": event_logger.JSON_SCHEMA_VERSION,
            "result": "failure",
            "errors": [
                {
                    "message": expected_error.msg,
                    "message_code": expected_error.name,
                    "service": None,
                    "type": "system",
                }
            ],
            "failed_services": ["bogus"] if not uid and is_attached else [],
            "needs_reboot": False,
            "processed_services": [],
            "warnings": [],
        }
        assert expected == json.loads(fake_stdout.getvalue())
Exemplo n.º 7
0
    DEFAULT_STATUS,
    TxtColor,
    colorize_commands,
    format_tabular,
)

DEFAULT_CFG_STATUS = {
    "execution_status": DEFAULT_STATUS["execution_status"],
    "execution_details": DEFAULT_STATUS["execution_details"],
}
M_PATH = "uaclient.entitlements."

ALL_RESOURCES_AVAILABLE = [{
    "name": name,
    "available": True
} for name in valid_services(cfg=UAConfig(), allow_beta=True)]


@pytest.fixture(params=[True, False])
def status_dict_attached(request):
    status = DEFAULT_STATUS.copy()

    # The following are required so we don't get an "unattached" error
    status["attached"] = True
    status["expires"] = "expires"
    status["account"] = {"name": ""}
    status["contract"] = {
        "name": "",
        "tech_support_level": UserFacingStatus.INAPPLICABLE.value,
    }