-
Notifications
You must be signed in to change notification settings - Fork 159
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
391 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,391 @@ | ||
# -*- coding: utf-8 -*- | ||
""" | ||
test_related_events.py | ||
~~~~~~~~~~~~~~~~~~~~~~ | ||
Specific tests to validate the "related events" logic used by certain events | ||
inside hyper-h2. | ||
""" | ||
import h2.connection | ||
import h2.events | ||
|
||
|
||
class TestRelatedEvents(object): | ||
""" | ||
Related events correlate all those events that happen on a single frame. | ||
""" | ||
example_request_headers = [ | ||
(':authority', 'example.com'), | ||
(':path', '/'), | ||
(':scheme', 'https'), | ||
(':method', 'GET'), | ||
] | ||
|
||
example_response_headers = [ | ||
(':status', '200'), | ||
('server', 'fake-serv/0.1.0') | ||
] | ||
|
||
informational_response_headers = [ | ||
(':status', '100'), | ||
('server', 'fake-serv/0.1.0') | ||
] | ||
|
||
example_trailers = [ | ||
('another', 'field'), | ||
] | ||
|
||
def test_request_received_related_all(self, frame_factory): | ||
""" | ||
RequestReceived has two possible related events: PriorityUpdated and | ||
StreamEnded, all fired when a single HEADERS frame is received. | ||
""" | ||
c = h2.connection.H2Connection(client_side=False) | ||
c.initiate_connection() | ||
c.receive_data(frame_factory.preamble()) | ||
|
||
input_frame = frame_factory.build_headers_frame( | ||
headers=self.example_request_headers, | ||
flags=['END_STREAM', 'PRIORITY'], | ||
stream_weight=15, | ||
depends_on=0, | ||
exclusive=False, | ||
) | ||
events = c.receive_data(input_frame.serialize()) | ||
|
||
assert len(events) == 3 | ||
base_event = events[0] | ||
other_events = events[1:] | ||
|
||
assert base_event.stream_ended in other_events | ||
assert isinstance(base_event.stream_ended, h2.events.StreamEnded) | ||
assert base_event.priority_updated in other_events | ||
assert isinstance( | ||
base_event.priority_updated, h2.events.PriorityUpdated | ||
) | ||
|
||
def test_request_received_related_priority(self, frame_factory): | ||
""" | ||
RequestReceived can be related to PriorityUpdated. | ||
""" | ||
c = h2.connection.H2Connection(client_side=False) | ||
c.initiate_connection() | ||
c.receive_data(frame_factory.preamble()) | ||
|
||
input_frame = frame_factory.build_headers_frame( | ||
headers=self.example_request_headers, | ||
flags=['PRIORITY'], | ||
stream_weight=15, | ||
depends_on=0, | ||
exclusive=False, | ||
) | ||
events = c.receive_data(input_frame.serialize()) | ||
|
||
assert len(events) == 2 | ||
base_event = events[0] | ||
priority_updated_event = events[1] | ||
|
||
assert base_event.priority_updated is priority_updated_event | ||
assert base_event.stream_ended is None | ||
assert isinstance( | ||
base_event.priority_updated, h2.events.PriorityUpdated | ||
) | ||
|
||
def test_request_received_related_stream_ended(self, frame_factory): | ||
""" | ||
RequestReceived can be related to StreamEnded. | ||
""" | ||
c = h2.connection.H2Connection(client_side=False) | ||
c.initiate_connection() | ||
c.receive_data(frame_factory.preamble()) | ||
|
||
input_frame = frame_factory.build_headers_frame( | ||
headers=self.example_request_headers, | ||
flags=['END_STREAM'], | ||
) | ||
events = c.receive_data(input_frame.serialize()) | ||
|
||
assert len(events) == 2 | ||
base_event = events[0] | ||
stream_ended_event = events[1] | ||
|
||
assert base_event.stream_ended is stream_ended_event | ||
assert base_event.priority_updated is None | ||
assert isinstance(base_event.stream_ended, h2.events.StreamEnded) | ||
|
||
def test_response_received_related_nothing(self, frame_factory): | ||
""" | ||
ResponseReceived is ordinarily related to no events. | ||
""" | ||
c = h2.connection.H2Connection() | ||
c.initiate_connection() | ||
c.send_headers(stream_id=1, headers=self.example_request_headers) | ||
|
||
input_frame = frame_factory.build_headers_frame( | ||
headers=self.example_response_headers, | ||
) | ||
events = c.receive_data(input_frame.serialize()) | ||
|
||
assert len(events) == 1 | ||
base_event = events[0] | ||
|
||
assert base_event.stream_ended is None | ||
assert base_event.priority_updated is None | ||
|
||
def test_response_received_related_all(self, frame_factory): | ||
""" | ||
ResponseReceived has two possible related events: PriorityUpdated and | ||
StreamEnded, all fired when a single HEADERS frame is received. | ||
""" | ||
c = h2.connection.H2Connection() | ||
c.initiate_connection() | ||
c.send_headers(stream_id=1, headers=self.example_request_headers) | ||
|
||
input_frame = frame_factory.build_headers_frame( | ||
headers=self.example_response_headers, | ||
flags=['END_STREAM', 'PRIORITY'], | ||
stream_weight=15, | ||
depends_on=0, | ||
exclusive=False, | ||
) | ||
events = c.receive_data(input_frame.serialize()) | ||
|
||
assert len(events) == 3 | ||
base_event = events[0] | ||
other_events = events[1:] | ||
|
||
assert base_event.stream_ended in other_events | ||
assert isinstance(base_event.stream_ended, h2.events.StreamEnded) | ||
assert base_event.priority_updated in other_events | ||
assert isinstance( | ||
base_event.priority_updated, h2.events.PriorityUpdated | ||
) | ||
|
||
def test_response_received_related_priority(self, frame_factory): | ||
""" | ||
ResponseReceived can be related to PriorityUpdated. | ||
""" | ||
c = h2.connection.H2Connection() | ||
c.initiate_connection() | ||
c.send_headers(stream_id=1, headers=self.example_request_headers) | ||
|
||
input_frame = frame_factory.build_headers_frame( | ||
headers=self.example_response_headers, | ||
flags=['PRIORITY'], | ||
stream_weight=15, | ||
depends_on=0, | ||
exclusive=False, | ||
) | ||
events = c.receive_data(input_frame.serialize()) | ||
|
||
assert len(events) == 2 | ||
base_event = events[0] | ||
priority_updated_event = events[1] | ||
|
||
assert base_event.priority_updated is priority_updated_event | ||
assert base_event.stream_ended is None | ||
assert isinstance( | ||
base_event.priority_updated, h2.events.PriorityUpdated | ||
) | ||
|
||
def test_response_received_related_stream_ended(self, frame_factory): | ||
""" | ||
ResponseReceived can be related to StreamEnded. | ||
""" | ||
c = h2.connection.H2Connection() | ||
c.initiate_connection() | ||
c.send_headers(stream_id=1, headers=self.example_request_headers) | ||
|
||
input_frame = frame_factory.build_headers_frame( | ||
headers=self.example_response_headers, | ||
flags=['END_STREAM'], | ||
) | ||
events = c.receive_data(input_frame.serialize()) | ||
|
||
assert len(events) == 2 | ||
base_event = events[0] | ||
stream_ended_event = events[1] | ||
|
||
assert base_event.stream_ended is stream_ended_event | ||
assert base_event.priority_updated is None | ||
assert isinstance(base_event.stream_ended, h2.events.StreamEnded) | ||
|
||
def test_trailers_received_related_nothing(self, frame_factory): | ||
""" | ||
TrailersReceived is normally related to no events. | ||
""" | ||
c = h2.connection.H2Connection() | ||
c.initiate_connection() | ||
c.send_headers(stream_id=1, headers=self.example_request_headers) | ||
|
||
f = frame_factory.build_headers_frame( | ||
headers=self.example_response_headers, | ||
) | ||
c.receive_data(f.serialize()) | ||
|
||
input_frame = frame_factory.build_headers_frame( | ||
headers=self.example_trailers, | ||
) | ||
events = c.receive_data(input_frame.serialize()) | ||
|
||
assert len(events) == 1 | ||
base_event = events[0] | ||
|
||
assert base_event.stream_ended is None | ||
assert base_event.priority_updated is None | ||
|
||
def test_trailers_received_related_all(self, frame_factory): | ||
""" | ||
TrailersReceived has two possible related events: PriorityUpdated and | ||
StreamEnded, all fired when a single HEADERS frame is received. | ||
""" | ||
c = h2.connection.H2Connection() | ||
c.initiate_connection() | ||
c.send_headers(stream_id=1, headers=self.example_request_headers) | ||
|
||
f = frame_factory.build_headers_frame( | ||
headers=self.example_response_headers, | ||
) | ||
c.receive_data(f.serialize()) | ||
|
||
input_frame = frame_factory.build_headers_frame( | ||
headers=self.example_trailers, | ||
flags=['END_STREAM', 'PRIORITY'], | ||
stream_weight=15, | ||
depends_on=0, | ||
exclusive=False, | ||
) | ||
events = c.receive_data(input_frame.serialize()) | ||
|
||
assert len(events) == 3 | ||
base_event = events[0] | ||
other_events = events[1:] | ||
|
||
assert base_event.stream_ended in other_events | ||
assert isinstance(base_event.stream_ended, h2.events.StreamEnded) | ||
assert base_event.priority_updated in other_events | ||
assert isinstance( | ||
base_event.priority_updated, h2.events.PriorityUpdated | ||
) | ||
|
||
def test_trailers_received_related_stream_ended(self, frame_factory): | ||
""" | ||
TrailersReceived can be related to StreamEnded by itself. | ||
""" | ||
c = h2.connection.H2Connection() | ||
c.initiate_connection() | ||
c.send_headers(stream_id=1, headers=self.example_request_headers) | ||
|
||
f = frame_factory.build_headers_frame( | ||
headers=self.example_response_headers, | ||
) | ||
c.receive_data(f.serialize()) | ||
|
||
input_frame = frame_factory.build_headers_frame( | ||
headers=self.example_trailers, | ||
flags=['END_STREAM'], | ||
) | ||
events = c.receive_data(input_frame.serialize()) | ||
|
||
assert len(events) == 2 | ||
base_event = events[0] | ||
stream_ended_event = events[1] | ||
|
||
assert base_event.stream_ended is stream_ended_event | ||
assert base_event.priority_updated is None | ||
assert isinstance(base_event.stream_ended, h2.events.StreamEnded) | ||
|
||
def test_informational_response_related_nothing(self, frame_factory): | ||
""" | ||
InformationalResponseReceived in the standard case is related to | ||
nothing. | ||
""" | ||
c = h2.connection.H2Connection() | ||
c.initiate_connection() | ||
c.send_headers(stream_id=1, headers=self.example_request_headers) | ||
|
||
input_frame = frame_factory.build_headers_frame( | ||
headers=self.informational_response_headers, | ||
) | ||
events = c.receive_data(input_frame.serialize()) | ||
|
||
assert len(events) == 1 | ||
base_event = events[0] | ||
|
||
assert base_event.priority_updated is None | ||
|
||
def test_informational_response_received_related_all(self, frame_factory): | ||
""" | ||
InformationalResponseReceived has one possible related event: | ||
PriorityUpdated, fired when a single HEADERS frame is received. | ||
""" | ||
c = h2.connection.H2Connection() | ||
c.initiate_connection() | ||
c.send_headers(stream_id=1, headers=self.example_request_headers) | ||
|
||
input_frame = frame_factory.build_headers_frame( | ||
headers=self.informational_response_headers, | ||
flags=['PRIORITY'], | ||
stream_weight=15, | ||
depends_on=0, | ||
exclusive=False, | ||
) | ||
events = c.receive_data(input_frame.serialize()) | ||
|
||
assert len(events) == 2 | ||
base_event = events[0] | ||
priority_updated_event = events[1] | ||
|
||
assert base_event.priority_updated is priority_updated_event | ||
assert isinstance( | ||
base_event.priority_updated, h2.events.PriorityUpdated | ||
) | ||
|
||
def test_data_received_normally_relates_to_nothing(self, frame_factory): | ||
""" | ||
A plain DATA frame leads to DataReceieved with no related events. | ||
""" | ||
c = h2.connection.H2Connection() | ||
c.initiate_connection() | ||
c.send_headers(stream_id=1, headers=self.example_request_headers) | ||
|
||
f = frame_factory.build_headers_frame( | ||
headers=self.example_response_headers, | ||
) | ||
c.receive_data(f.serialize()) | ||
|
||
input_frame = frame_factory.build_data_frame( | ||
data=b'some data', | ||
) | ||
events = c.receive_data(input_frame.serialize()) | ||
|
||
assert len(events) == 1 | ||
base_event = events[0] | ||
|
||
assert base_event.stream_ended is None | ||
|
||
def test_data_received_related_stream_ended(self, frame_factory): | ||
""" | ||
DataReceived can be related to StreamEnded by itself. | ||
""" | ||
c = h2.connection.H2Connection() | ||
c.initiate_connection() | ||
c.send_headers(stream_id=1, headers=self.example_request_headers) | ||
|
||
f = frame_factory.build_headers_frame( | ||
headers=self.example_response_headers, | ||
) | ||
c.receive_data(f.serialize()) | ||
|
||
input_frame = frame_factory.build_data_frame( | ||
data=b'some data', | ||
flags=['END_STREAM'], | ||
) | ||
events = c.receive_data(input_frame.serialize()) | ||
|
||
assert len(events) == 2 | ||
base_event = events[0] | ||
stream_ended_event = events[1] | ||
|
||
assert base_event.stream_ended is stream_ended_event | ||
assert isinstance(base_event.stream_ended, h2.events.StreamEnded) |