import mock
from urllib.error import HTTPError, URLError
from io import BytesIO

import pytest

from uaclient import util
from uaclient.serviceclient import UAServiceClient


class OurServiceClientException(Exception):
    def __init__(self, exc, details):
        self.exc = exc
        self.details = details


class OurServiceClient(UAServiceClient):
    @property
    def api_error_cls(self):
        return OurServiceClientException

    @property
    def cfg_url_base_attr(self):
        return "url_attr"


class TestRequestUrl:

    # TODO: Non error-path tests

    @pytest.mark.parametrize(
        "fp,expected_exception,expected_attrs",
        (
            (BytesIO(), util.UrlError, {"code": 619}),
            (
                BytesIO(b'{"a": "b"}'),
                OurServiceClientException,
                {"details": {"a": "b"}},
            ),
        ),
    )
    @mock.patch("uaclient.serviceclient.util.readurl")
    def test_httperror_handling(
        self, m_readurl, fp, expected_exception, expected_attrs
    ):
        m_readurl.side_effect = HTTPError(None, 619, None, None, fp)

        client = OurServiceClient(cfg=mock.Mock(url_attr="http://example.com"))
        with pytest.raises(expected_exception) as excinfo:
            client.request_url("/")

        for attr, expected_value in expected_attrs.items():
            assert expected_value == getattr(excinfo.value, attr)

    @mock.patch("uaclient.serviceclient.util.readurl")
    def test_urlerror_handling(self, m_readurl):
        m_readurl.side_effect = URLError(None)

        client = OurServiceClient(cfg=mock.Mock(url_attr="http://example.com"))
        with pytest.raises(util.UrlError) as excinfo:
            client.request_url("/")

        assert excinfo.value.code is None
