1
1
import asyncio
2
2
import json
3
3
import time
4
+ from unittest .mock import patch
4
5
5
6
import pytest
6
7
@@ -57,8 +58,7 @@ async def handle(self, body):
57
58
@pytest .mark .asyncio
58
59
async def test_per_scope_consumers ():
59
60
"""
60
- Tests that a distinct consumer is used per scope, with AsyncHttpConsumer as
61
- the example consumer class.
61
+ Tests that a distinct consumer is used per scope.
62
62
"""
63
63
64
64
class TestConsumer (AsyncHttpConsumer ):
@@ -68,7 +68,6 @@ def __init__(self):
68
68
69
69
async def handle (self , body ):
70
70
body = f"{ self .__class__ .__name__ } { id (self )} { self .time } "
71
-
72
71
await self .send_response (
73
72
200 ,
74
73
body .encode ("utf-8" ),
@@ -77,27 +76,21 @@ async def handle(self, body):
77
76
78
77
app = TestConsumer .as_asgi ()
79
78
80
- # Open a connection
81
79
communicator = HttpCommunicator (app , method = "GET" , path = "/test/" )
82
80
response = await communicator .get_response ()
83
81
assert response ["status" ] == 200
84
82
85
- # And another one.
86
83
communicator = HttpCommunicator (app , method = "GET" , path = "/test2/" )
87
84
second_response = await communicator .get_response ()
88
85
assert second_response ["status" ] == 200
89
-
90
86
assert response ["body" ] != second_response ["body" ]
91
87
92
88
93
89
@pytest .mark .django_db (transaction = True )
94
90
@pytest .mark .asyncio
95
91
async def test_async_http_consumer_future ():
96
92
"""
97
- Regression test for channels accepting only coroutines. The ASGI specification
98
- states that the `receive` and `send` arguments to an ASGI application should be
99
- "awaitable callable" objects. That includes non-coroutine functions that return
100
- Futures.
93
+ Regression test for channels accepting only coroutines.
101
94
"""
102
95
103
96
class TestConsumer (AsyncHttpConsumer ):
@@ -110,7 +103,6 @@ async def handle(self, body):
110
103
111
104
app = TestConsumer ()
112
105
113
- # Ensure the passed functions are specifically coroutines.
114
106
async def coroutine_app (scope , receive , send ):
115
107
async def receive_coroutine ():
116
108
return await asyncio .ensure_future (receive ())
@@ -126,7 +118,6 @@ async def send_coroutine(*args, **kwargs):
126
118
assert response ["status" ] == 200
127
119
assert response ["headers" ] == [(b"Content-Type" , b"text/plain" )]
128
120
129
- # Ensure the passed functions are "Awaitable Callables" and NOT coroutines.
130
121
async def awaitable_callable_app (scope , receive , send ):
131
122
def receive_awaitable_callable ():
132
123
return asyncio .ensure_future (receive ())
@@ -136,9 +127,46 @@ def send_awaitable_callable(*args, **kwargs):
136
127
137
128
await app (scope , receive_awaitable_callable , send_awaitable_callable )
138
129
139
- # Open a connection
140
130
communicator = HttpCommunicator (awaitable_callable_app , method = "GET" , path = "/" )
141
131
response = await communicator .get_response ()
142
132
assert response ["body" ] == b"42"
143
133
assert response ["status" ] == 200
144
134
assert response ["headers" ] == [(b"Content-Type" , b"text/plain" )]
135
+
136
+
137
+ @pytest .mark .django_db (transaction = True )
138
+ @pytest .mark .asyncio
139
+ async def test_error_logging ():
140
+ """Regression test for error logging."""
141
+
142
+ class TestConsumer (AsyncHttpConsumer ):
143
+ async def handle (self , body ):
144
+ raise AssertionError ("Error correctly raised" )
145
+
146
+ communicator = HttpCommunicator (TestConsumer (), "GET" , "/" )
147
+ with patch ("channels.generic.http.logger.error" ) as mock_logger_error :
148
+ try :
149
+ await communicator .get_response (timeout = 0.05 )
150
+ except AssertionError :
151
+ pass
152
+ args , _ = mock_logger_error .call_args
153
+ assert "Error in handle()" in args [0 ]
154
+ assert "AssertionError: Error correctly raised" in args [0 ]
155
+
156
+
157
+ @pytest .mark .django_db (transaction = True )
158
+ @pytest .mark .asyncio
159
+ async def test_error_handling_and_send_response ():
160
+ """Regression test to check error handling."""
161
+
162
+ class TestConsumer (AsyncHttpConsumer ):
163
+ async def handle (self , body ):
164
+ raise AssertionError ("Error correctly raised" )
165
+
166
+ communicator = HttpCommunicator (TestConsumer (), "GET" , "/" )
167
+ with patch .object (AsyncHttpConsumer , "send_response" ) as mock_send_response :
168
+ try :
169
+ await communicator .get_response (timeout = 0.05 )
170
+ except AssertionError :
171
+ pass
172
+ mock_send_response .assert_called_once_with (500 , b"Internal Server Error" )
0 commit comments