| import pytest |
|
|
| from .._events import * |
| from .._state import * |
| from .._state import _SWITCH_CONNECT, _SWITCH_UPGRADE, ConnectionState |
| from .._util import LocalProtocolError |
|
|
|
|
| def test_ConnectionState(): |
| cs = ConnectionState() |
|
|
| |
|
|
| assert cs.states == {CLIENT: IDLE, SERVER: IDLE} |
|
|
| cs.process_event(CLIENT, Request) |
| |
| assert cs.states == {CLIENT: SEND_BODY, SERVER: SEND_RESPONSE} |
|
|
| |
| with pytest.raises(LocalProtocolError): |
| cs.process_event(CLIENT, Request) |
| assert cs.states == {CLIENT: SEND_BODY, SERVER: SEND_RESPONSE} |
|
|
| cs.process_event(SERVER, InformationalResponse) |
| assert cs.states == {CLIENT: SEND_BODY, SERVER: SEND_RESPONSE} |
|
|
| cs.process_event(SERVER, Response) |
| assert cs.states == {CLIENT: SEND_BODY, SERVER: SEND_BODY} |
|
|
| cs.process_event(CLIENT, EndOfMessage) |
| cs.process_event(SERVER, EndOfMessage) |
| assert cs.states == {CLIENT: DONE, SERVER: DONE} |
|
|
| |
|
|
| cs.process_event(SERVER, ConnectionClosed) |
| assert cs.states == {CLIENT: MUST_CLOSE, SERVER: CLOSED} |
|
|
|
|
| def test_ConnectionState_keep_alive(): |
| |
| cs = ConnectionState() |
| cs.process_event(CLIENT, Request) |
| cs.process_keep_alive_disabled() |
| cs.process_event(CLIENT, EndOfMessage) |
| assert cs.states == {CLIENT: MUST_CLOSE, SERVER: SEND_RESPONSE} |
|
|
| cs.process_event(SERVER, Response) |
| cs.process_event(SERVER, EndOfMessage) |
| assert cs.states == {CLIENT: MUST_CLOSE, SERVER: MUST_CLOSE} |
|
|
|
|
| def test_ConnectionState_keep_alive_in_DONE(): |
| |
| |
| |
| cs = ConnectionState() |
| cs.process_event(CLIENT, Request) |
| cs.process_event(CLIENT, EndOfMessage) |
| assert cs.states[CLIENT] is DONE |
| cs.process_keep_alive_disabled() |
| assert cs.states[CLIENT] is MUST_CLOSE |
|
|
|
|
| def test_ConnectionState_switch_denied(): |
| for switch_type in (_SWITCH_CONNECT, _SWITCH_UPGRADE): |
| for deny_early in (True, False): |
| cs = ConnectionState() |
| cs.process_client_switch_proposal(switch_type) |
| cs.process_event(CLIENT, Request) |
| cs.process_event(CLIENT, Data) |
| assert cs.states == {CLIENT: SEND_BODY, SERVER: SEND_RESPONSE} |
|
|
| assert switch_type in cs.pending_switch_proposals |
|
|
| if deny_early: |
| |
| cs.process_event(SERVER, Response) |
| assert not cs.pending_switch_proposals |
|
|
| cs.process_event(CLIENT, EndOfMessage) |
|
|
| if deny_early: |
| assert cs.states == {CLIENT: DONE, SERVER: SEND_BODY} |
| else: |
| assert cs.states == { |
| CLIENT: MIGHT_SWITCH_PROTOCOL, |
| SERVER: SEND_RESPONSE, |
| } |
|
|
| cs.process_event(SERVER, InformationalResponse) |
| assert cs.states == { |
| CLIENT: MIGHT_SWITCH_PROTOCOL, |
| SERVER: SEND_RESPONSE, |
| } |
|
|
| cs.process_event(SERVER, Response) |
| assert cs.states == {CLIENT: DONE, SERVER: SEND_BODY} |
| assert not cs.pending_switch_proposals |
|
|
|
|
| _response_type_for_switch = { |
| _SWITCH_UPGRADE: InformationalResponse, |
| _SWITCH_CONNECT: Response, |
| None: Response, |
| } |
|
|
|
|
| def test_ConnectionState_protocol_switch_accepted(): |
| for switch_event in [_SWITCH_UPGRADE, _SWITCH_CONNECT]: |
| cs = ConnectionState() |
| cs.process_client_switch_proposal(switch_event) |
| cs.process_event(CLIENT, Request) |
| cs.process_event(CLIENT, Data) |
| assert cs.states == {CLIENT: SEND_BODY, SERVER: SEND_RESPONSE} |
|
|
| cs.process_event(CLIENT, EndOfMessage) |
| assert cs.states == {CLIENT: MIGHT_SWITCH_PROTOCOL, SERVER: SEND_RESPONSE} |
|
|
| cs.process_event(SERVER, InformationalResponse) |
| assert cs.states == {CLIENT: MIGHT_SWITCH_PROTOCOL, SERVER: SEND_RESPONSE} |
|
|
| cs.process_event(SERVER, _response_type_for_switch[switch_event], switch_event) |
| assert cs.states == {CLIENT: SWITCHED_PROTOCOL, SERVER: SWITCHED_PROTOCOL} |
|
|
|
|
| def test_ConnectionState_double_protocol_switch(): |
| |
| |
| for server_switch in [None, _SWITCH_UPGRADE, _SWITCH_CONNECT]: |
| cs = ConnectionState() |
| cs.process_client_switch_proposal(_SWITCH_UPGRADE) |
| cs.process_client_switch_proposal(_SWITCH_CONNECT) |
| cs.process_event(CLIENT, Request) |
| cs.process_event(CLIENT, EndOfMessage) |
| assert cs.states == {CLIENT: MIGHT_SWITCH_PROTOCOL, SERVER: SEND_RESPONSE} |
| cs.process_event( |
| SERVER, _response_type_for_switch[server_switch], server_switch |
| ) |
| if server_switch is None: |
| assert cs.states == {CLIENT: DONE, SERVER: SEND_BODY} |
| else: |
| assert cs.states == {CLIENT: SWITCHED_PROTOCOL, SERVER: SWITCHED_PROTOCOL} |
|
|
|
|
| def test_ConnectionState_inconsistent_protocol_switch(): |
| for client_switches, server_switch in [ |
| ([], _SWITCH_CONNECT), |
| ([], _SWITCH_UPGRADE), |
| ([_SWITCH_UPGRADE], _SWITCH_CONNECT), |
| ([_SWITCH_CONNECT], _SWITCH_UPGRADE), |
| ]: |
| cs = ConnectionState() |
| for client_switch in client_switches: |
| cs.process_client_switch_proposal(client_switch) |
| cs.process_event(CLIENT, Request) |
| with pytest.raises(LocalProtocolError): |
| cs.process_event(SERVER, Response, server_switch) |
|
|
|
|
| def test_ConnectionState_keepalive_protocol_switch_interaction(): |
| |
| cs = ConnectionState() |
| cs.process_client_switch_proposal(_SWITCH_UPGRADE) |
| cs.process_event(CLIENT, Request) |
| cs.process_keep_alive_disabled() |
| cs.process_event(CLIENT, Data) |
| assert cs.states == {CLIENT: SEND_BODY, SERVER: SEND_RESPONSE} |
|
|
| |
| cs.process_event(CLIENT, EndOfMessage) |
| assert cs.states == {CLIENT: MIGHT_SWITCH_PROTOCOL, SERVER: SEND_RESPONSE} |
|
|
| |
| cs.process_event(SERVER, Response) |
| assert cs.states == {CLIENT: MUST_CLOSE, SERVER: SEND_BODY} |
|
|
|
|
| def test_ConnectionState_reuse(): |
| cs = ConnectionState() |
|
|
| with pytest.raises(LocalProtocolError): |
| cs.start_next_cycle() |
|
|
| cs.process_event(CLIENT, Request) |
| cs.process_event(CLIENT, EndOfMessage) |
|
|
| with pytest.raises(LocalProtocolError): |
| cs.start_next_cycle() |
|
|
| cs.process_event(SERVER, Response) |
| cs.process_event(SERVER, EndOfMessage) |
|
|
| cs.start_next_cycle() |
| assert cs.states == {CLIENT: IDLE, SERVER: IDLE} |
|
|
| |
|
|
| cs.process_event(CLIENT, Request) |
| cs.process_keep_alive_disabled() |
| cs.process_event(CLIENT, EndOfMessage) |
| cs.process_event(SERVER, Response) |
| cs.process_event(SERVER, EndOfMessage) |
|
|
| with pytest.raises(LocalProtocolError): |
| cs.start_next_cycle() |
|
|
| |
|
|
| cs = ConnectionState() |
| cs.process_event(CLIENT, Request) |
| cs.process_event(CLIENT, EndOfMessage) |
| cs.process_event(CLIENT, ConnectionClosed) |
| cs.process_event(SERVER, Response) |
| cs.process_event(SERVER, EndOfMessage) |
|
|
| with pytest.raises(LocalProtocolError): |
| cs.start_next_cycle() |
|
|
| |
|
|
| cs = ConnectionState() |
| cs.process_client_switch_proposal(_SWITCH_UPGRADE) |
| cs.process_event(CLIENT, Request) |
| cs.process_event(CLIENT, EndOfMessage) |
| cs.process_event(SERVER, InformationalResponse, _SWITCH_UPGRADE) |
|
|
| with pytest.raises(LocalProtocolError): |
| cs.start_next_cycle() |
|
|
| |
|
|
| cs = ConnectionState() |
| cs.process_client_switch_proposal(_SWITCH_UPGRADE) |
| cs.process_event(CLIENT, Request) |
| cs.process_event(CLIENT, EndOfMessage) |
| cs.process_event(SERVER, Response) |
| cs.process_event(SERVER, EndOfMessage) |
|
|
| cs.start_next_cycle() |
| assert cs.states == {CLIENT: IDLE, SERVER: IDLE} |
|
|
|
|
| def test_server_request_is_illegal(): |
| |
| |
| cs = ConnectionState() |
| with pytest.raises(LocalProtocolError): |
| cs.process_event(SERVER, Request) |
|
|