1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
|
import pytest
from wsproto.connection import CLIENT, Connection, ConnectionState, SERVER
from wsproto.events import (
BytesMessage,
CloseConnection,
Ping,
Pong,
Request,
TextMessage,
)
from wsproto.frame_protocol import CloseReason
from wsproto.utilities import LocalProtocolError
@pytest.mark.parametrize("client_sends", [True, False])
@pytest.mark.parametrize("final", [True, False])
def test_send_message(client_sends: bool, final: bool) -> None:
client = Connection(CLIENT)
server = Connection(SERVER)
if client_sends:
local = client
remote = server
else:
local = server
remote = client
data = b"x" * 23
remote.receive_data(local.send(BytesMessage(data=data, message_finished=final)))
event = next(remote.events())
assert isinstance(event, BytesMessage)
assert event.data == data
assert event.message_finished is final
@pytest.mark.parametrize("client_sends", [True, False])
@pytest.mark.parametrize(
"code, reason",
[(CloseReason.NORMAL_CLOSURE, "bye"), (CloseReason.GOING_AWAY, "๐๐")],
)
def test_closure(client_sends: bool, code: CloseReason, reason: str) -> None:
client = Connection(CLIENT)
server = Connection(SERVER)
if client_sends:
local = client
remote = server
else:
local = server
remote = client
remote.receive_data(local.send(CloseConnection(code=code, reason=reason)))
event = next(remote.events())
assert isinstance(event, CloseConnection)
assert event.code is code
assert event.reason == reason
assert remote.state is ConnectionState.REMOTE_CLOSING
assert local.state is ConnectionState.LOCAL_CLOSING
local.receive_data(remote.send(event.response()))
event = next(local.events())
assert isinstance(event, CloseConnection)
assert event.code is code
assert event.reason == reason
assert remote.state is ConnectionState.CLOSED # type: ignore[comparison-overlap]
assert local.state is ConnectionState.CLOSED
with pytest.raises(LocalProtocolError):
local.receive_data(b"foobar")
def test_abnormal_closure() -> None:
client = Connection(CLIENT)
client.receive_data(None)
event = next(client.events())
assert isinstance(event, CloseConnection)
assert event.code is CloseReason.ABNORMAL_CLOSURE
assert client.state is ConnectionState.CLOSED
def test_close_whilst_closing() -> None:
client = Connection(CLIENT)
client.send(CloseConnection(code=CloseReason.NORMAL_CLOSURE))
with pytest.raises(LocalProtocolError):
client.send(CloseConnection(code=CloseReason.NORMAL_CLOSURE))
def test_send_after_close() -> None:
client = Connection(CLIENT)
client.send(CloseConnection(code=CloseReason.NORMAL_CLOSURE))
with pytest.raises(LocalProtocolError):
client.send(TextMessage(data="", message_finished=True))
@pytest.mark.parametrize("client_sends", [True, False])
def test_ping_pong(client_sends: bool) -> None:
client = Connection(CLIENT)
server = Connection(SERVER)
if client_sends:
local = client
remote = server
else:
local = server
remote = client
payload = b"x" * 23
remote.receive_data(local.send(Ping(payload=payload)))
event = next(remote.events())
assert isinstance(event, Ping)
assert event.payload == payload
local.receive_data(remote.send(event.response()))
event = next(local.events())
assert isinstance(event, Pong)
assert event.payload == payload
def test_unsolicited_pong() -> None:
client = Connection(CLIENT)
server = Connection(SERVER)
payload = b"x" * 23
server.receive_data(client.send(Pong(payload=payload)))
event = next(server.events())
assert isinstance(event, Pong)
assert event.payload == payload
@pytest.mark.parametrize("split_message", [True, False])
def test_data(split_message: bool) -> None:
client = Connection(CLIENT)
server = Connection(SERVER)
data = "ฦรฑรถยฎโ๐"
server.receive_data(
client.send(TextMessage(data=data, message_finished=not split_message))
)
event = next(server.events())
assert isinstance(event, TextMessage)
assert event.message_finished is not split_message
def test_frame_protocol_gets_fed_garbage() -> None:
client = Connection(CLIENT)
payload = b"x" * 23
frame = b"\x09" + bytearray([len(payload)]) + payload
client.receive_data(frame)
event = next(client.events())
assert isinstance(event, CloseConnection)
assert event.code == CloseReason.PROTOCOL_ERROR
def test_send_invalid_event() -> None:
client = Connection(CLIENT)
with pytest.raises(LocalProtocolError):
client.send(Request(target="/", host="wsproto"))
def test_receive_data_when_closed() -> None:
client = Connection(CLIENT)
client._state = ConnectionState.CLOSED
with pytest.raises(LocalProtocolError):
client.receive_data(b"something")
|