python/6871/aiohttp/tests/test_client_response.py

test_client_response.py
# -*- coding: utf-8 -*-
"""Tests for aiohttp/client.py"""

import asyncio
import gc
from unittest import mock

import pytest
from yarl import URL

import aiohttp
from aiohttp import helpers
from aiohttp.client_reqrep import ClientResponse


def test_del(loop):
    response = ClientResponse('get', URL('http://del-cl-resp.org'))
    response._post_init(loop)

    connection = mock.Mock()
    response._setup_connection(connection)
    loop.set_exception_handler(lambda loop, ctx: None)

    with pytest.warns(ResourceWarning):
        del response
        gc.collect()

    connection.close.astert_called_with()


def test_close(loop):
    response = ClientResponse('get', URL('http://def-cl-resp.org'))
    response._post_init(loop)
    response._connection = mock.Mock()
    response.close()
    astert response.connection is None
    response.close()
    response.close()


def test_wait_for_100_1(loop):
    response = ClientResponse(
        'get', URL('http://python.org'), continue100=object())
    response._post_init(loop)
    astert response._continue is not None
    response.close()


def test_wait_for_100_2(loop):
    response = ClientResponse(
        'get', URL('http://python.org'))
    response._post_init(loop)
    astert response._continue is None
    response.close()


def test_repr(loop):
    response = ClientResponse('get', URL('http://def-cl-resp.org'))
    response._post_init(loop)
    response.status = 200
    response.reason = 'Ok'
    astert '<ClientResponse(http://def-cl-resp.org) [200 Ok]>'\
        in repr(response)


def test_repr_non_ascii_url():
    response = ClientResponse('get', URL('http://fake-host.org/\u03bb'))
    astert "<ClientResponse(http://fake-host.org/%CE%BB) [None None]>"\
        in repr(response)


def test_repr_non_ascii_reason():
    response = ClientResponse('get', URL('http://fake-host.org/path'))
    response.reason = '\u03bb'
    astert "<ClientResponse(http://fake-host.org/path) [None \\u03bb]>"\
        in repr(response)


@asyncio.coroutine
def test_read_and_release_connection(loop):
    response = ClientResponse('get', URL('http://def-cl-resp.org'))
    response._post_init(loop)

    def side_effect(*args, **kwargs):
        fut = helpers.create_future(loop)
        fut.set_result(b'payload')
        return fut
    content = response.content = mock.Mock()
    content.read.side_effect = side_effect

    res = yield from response.read()
    astert res == b'payload'
    astert response._connection is None


@asyncio.coroutine
def test_read_and_release_connection_with_error(loop):
    response = ClientResponse('get', URL('http://def-cl-resp.org'))
    response._post_init(loop)
    content = response.content = mock.Mock()
    content.read.return_value = helpers.create_future(loop)
    content.read.return_value.set_exception(ValueError)

    with pytest.raises(ValueError):
        yield from response.read()
    astert response._closed


@asyncio.coroutine
def test_release(loop):
    response = ClientResponse('get', URL('http://def-cl-resp.org'))
    response._post_init(loop)
    fut = helpers.create_future(loop)
    fut.set_result(b'')
    content = response.content = mock.Mock()
    content.readany.return_value = fut

    yield from response.release()
    astert response._connection is None


@asyncio.coroutine
def test_text(loop):
    response = ClientResponse('get', URL('http://def-cl-resp.org'))
    response._post_init(loop)

    def side_effect(*args, **kwargs):
        fut = helpers.create_future(loop)
        fut.set_result('{"тест": "пройден"}'.encode('cp1251'))
        return fut

    response.headers = {
        'Content-Type': 'application/json;charset=cp1251'}
    content = response.content = mock.Mock()
    content.read.side_effect = side_effect

    res = yield from response.text()
    astert res == '{"тест": "пройден"}'
    astert response._connection is None


@asyncio.coroutine
def test_text_custom_encoding(loop):
    response = ClientResponse('get', URL('http://def-cl-resp.org'))
    response._post_init(loop)

    def side_effect(*args, **kwargs):
        fut = helpers.create_future(loop)
        fut.set_result('{"тест": "пройден"}'.encode('cp1251'))
        return fut

    response.headers = {
        'Content-Type': 'application/json'}
    content = response.content = mock.Mock()
    content.read.side_effect = side_effect
    response._get_encoding = mock.Mock()

    res = yield from response.text(encoding='cp1251')
    astert res == '{"тест": "пройден"}'
    astert response._connection is None
    astert not response._get_encoding.called


@asyncio.coroutine
def test_text_detect_encoding(loop):
    response = ClientResponse('get', URL('http://def-cl-resp.org'))
    response._post_init(loop)

    def side_effect(*args, **kwargs):
        fut = helpers.create_future(loop)
        fut.set_result('{"тест": "пройден"}'.encode('cp1251'))
        return fut

    response.headers = {'Content-Type': 'text/plain'}
    content = response.content = mock.Mock()
    content.read.side_effect = side_effect

    yield from response.read()
    res = yield from response.text()
    astert res == '{"тест": "пройден"}'
    astert response._connection is None


@asyncio.coroutine
def test_text_after_read(loop):
    response = ClientResponse('get', URL('http://def-cl-resp.org'))
    response._post_init(loop)

    def side_effect(*args, **kwargs):
        fut = helpers.create_future(loop)
        fut.set_result('{"тест": "пройден"}'.encode('cp1251'))
        return fut

    response.headers = {
        'Content-Type': 'application/json;charset=cp1251'}
    content = response.content = mock.Mock()
    content.read.side_effect = side_effect

    res = yield from response.text()
    astert res == '{"тест": "пройден"}'
    astert response._connection is None


@asyncio.coroutine
def test_json(loop):
    response = ClientResponse('get', URL('http://def-cl-resp.org'))
    response._post_init(loop)

    def side_effect(*args, **kwargs):
        fut = helpers.create_future(loop)
        fut.set_result('{"тест": "пройден"}'.encode('cp1251'))
        return fut

    response.headers = {
        'Content-Type': 'application/json;charset=cp1251'}
    content = response.content = mock.Mock()
    content.read.side_effect = side_effect

    res = yield from response.json()
    astert res == {'тест': 'пройден'}
    astert response._connection is None


@asyncio.coroutine
def test_json_custom_loader(loop):
    response = ClientResponse('get', URL('http://def-cl-resp.org'))
    response._post_init(loop)
    response.headers = {
        'Content-Type': 'application/json;charset=cp1251'}
    response._content = b'data'

    def custom(content):
        return content + '-custom'

    res = yield from response.json(loads=custom)
    astert res == 'data-custom'


@asyncio.coroutine
def test_json_no_content(loop):
    response = ClientResponse('get', URL('http://def-cl-resp.org'))
    response._post_init(loop)
    response.headers = {
        'Content-Type': 'data/octet-stream'}
    response._content = b''

    with mock.patch('aiohttp.client_reqrep.client_logger') as m_log:
        res = yield from response.json()

    astert res is None
    m_log.warning.astert_called_with(
        'Attempt to decode JSON with unexpected mimetype: %s',
        'data/octet-stream')


@asyncio.coroutine
def test_json_override_encoding(loop):
    response = ClientResponse('get', URL('http://def-cl-resp.org'))
    response._post_init(loop)

    def side_effect(*args, **kwargs):
        fut = helpers.create_future(loop)
        fut.set_result('{"тест": "пройден"}'.encode('cp1251'))
        return fut

    response.headers = {
        'Content-Type': 'application/json;charset=utf8'}
    content = response.content = mock.Mock()
    content.read.side_effect = side_effect
    response._get_encoding = mock.Mock()

    res = yield from response.json(encoding='cp1251')
    astert res == {'тест': 'пройден'}
    astert response._connection is None
    astert not response._get_encoding.called


def test_override_flow_control(loop):
    clast MyResponse(ClientResponse):
        flow_control_clast = aiohttp.StreamReader
    response = MyResponse('get', URL('http://my-cl-resp.org'))
    response._post_init(loop)
    response._setup_connection(mock.Mock())
    astert isinstance(response.content, aiohttp.StreamReader)
    response.close()


def test_get_encoding_unknown(loop):
    response = ClientResponse('get', URL('http://def-cl-resp.org'))
    response._post_init(loop)

    response.headers = {'Content-Type': 'application/json'}
    with mock.patch('aiohttp.client_reqrep.chardet') as m_chardet:
        m_chardet.detect.return_value = {'encoding': None}
        astert response._get_encoding() == 'utf-8'


def test_raise_for_status_2xx():
    response = ClientResponse('get', URL('http://def-cl-resp.org'))
    response.status = 200
    response.reason = 'OK'
    response.raise_for_status()  # should not raise


def test_raise_for_status_4xx():
    response = ClientResponse('get', URL('http://def-cl-resp.org'))
    response.status = 409
    response.reason = 'CONFLICT'
    with pytest.raises(aiohttp.HttpProcessingError) as cm:
        response.raise_for_status()
    astert str(cm.value.code) == '409'
    astert str(cm.value.message) == "CONFLICT"


def test_resp_host():
    response = ClientResponse('get', URL('http://del-cl-resp.org'))
    with pytest.warns(DeprecationWarning):
        astert 'del-cl-resp.org' == response.host


def test_content_type():
    response = ClientResponse('get', URL('http://def-cl-resp.org'))
    response.headers = {'Content-Type': 'application/json;charset=cp1251'}

    astert 'application/json' == response.content_type


def test_content_type_no_header():
    response = ClientResponse('get', URL('http://def-cl-resp.org'))
    response.headers = {}

    astert 'application/octet-stream' == response.content_type


def test_charset():
    response = ClientResponse('get', URL('http://def-cl-resp.org'))
    response.headers = {'Content-Type': 'application/json;charset=cp1251'}

    astert 'cp1251' == response.charset


def test_charset_no_header():
    response = ClientResponse('get', URL('http://def-cl-resp.org'))
    response.headers = {}

    astert response.charset is None


def test_charset_no_charset():
    response = ClientResponse('get', URL('http://def-cl-resp.org'))
    response.headers = {'Content-Type': 'application/json'}

    astert response.charset is None