tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_events.py (11765B)


      1 # -*- coding: utf-8 -*-
      2 """
      3 test_events.py
      4 ~~~~~~~~~~~~~~
      5 
      6 Specific tests for any function that is logically self-contained as part of
      7 events.py.
      8 """
      9 import inspect
     10 import sys
     11 
     12 from hypothesis import given
     13 from hypothesis.strategies import (
     14    integers, lists, tuples
     15 )
     16 import pytest
     17 
     18 import h2.errors
     19 import h2.events
     20 import h2.settings
     21 
     22 
     23 # We define a fairly complex Hypothesis strategy here. We want to build a list
     24 # of two tuples of (Setting, value). For Setting we want to make sure we can
     25 # handle settings that the rest of hyper knows nothing about, so we want to
     26 # use integers from 0 to (2**16-1). For values, they're from 0 to (2**32-1).
     27 # Define that strategy here for clarity.
     28 SETTINGS_STRATEGY = lists(
     29    tuples(
     30        integers(min_value=0, max_value=2**16-1),
     31        integers(min_value=0, max_value=2**32-1),
     32    )
     33 )
     34 
     35 
     36 class TestRemoteSettingsChanged(object):
     37    """
     38    Validate the function of the RemoteSettingsChanged event.
     39    """
     40    @given(SETTINGS_STRATEGY)
     41    def test_building_settings_from_scratch(self, settings_list):
     42        """
     43        Missing old settings are defaulted to None.
     44        """
     45        settings_dict = dict(settings_list)
     46        e = h2.events.RemoteSettingsChanged.from_settings(
     47            old_settings={},
     48            new_settings=settings_dict,
     49        )
     50 
     51        for setting, new_value in settings_dict.items():
     52            assert e.changed_settings[setting].setting == setting
     53            assert e.changed_settings[setting].original_value is None
     54            assert e.changed_settings[setting].new_value == new_value
     55 
     56    @given(SETTINGS_STRATEGY, SETTINGS_STRATEGY)
     57    def test_only_reports_changed_settings(self,
     58                                           old_settings_list,
     59                                           new_settings_list):
     60        """
     61        Settings that were not changed are not reported.
     62        """
     63        old_settings_dict = dict(old_settings_list)
     64        new_settings_dict = dict(new_settings_list)
     65        e = h2.events.RemoteSettingsChanged.from_settings(
     66            old_settings=old_settings_dict,
     67            new_settings=new_settings_dict,
     68        )
     69 
     70        assert len(e.changed_settings) == len(new_settings_dict)
     71        assert (
     72            sorted(list(e.changed_settings.keys())) ==
     73            sorted(list(new_settings_dict.keys()))
     74        )
     75 
     76    @given(SETTINGS_STRATEGY, SETTINGS_STRATEGY)
     77    def test_correctly_reports_changed_settings(self,
     78                                                old_settings_list,
     79                                                new_settings_list):
     80        """
     81        Settings that are changed are correctly reported.
     82        """
     83        old_settings_dict = dict(old_settings_list)
     84        new_settings_dict = dict(new_settings_list)
     85        e = h2.events.RemoteSettingsChanged.from_settings(
     86            old_settings=old_settings_dict,
     87            new_settings=new_settings_dict,
     88        )
     89 
     90        for setting, new_value in new_settings_dict.items():
     91            original_value = old_settings_dict.get(setting)
     92            assert e.changed_settings[setting].setting == setting
     93            assert e.changed_settings[setting].original_value == original_value
     94            assert e.changed_settings[setting].new_value == new_value
     95 
     96 
     97 class TestEventReprs(object):
     98    """
     99    Events have useful representations.
    100    """
    101    example_request_headers = [
    102        (':authority', 'example.com'),
    103        (':path', '/'),
    104        (':scheme', 'https'),
    105        (':method', 'GET'),
    106    ]
    107    example_informational_headers = [
    108        (':status', '100'),
    109        ('server', 'fake-serv/0.1.0')
    110    ]
    111    example_response_headers = [
    112        (':status', '200'),
    113        ('server', 'fake-serv/0.1.0')
    114    ]
    115 
    116    def test_requestreceived_repr(self):
    117        """
    118        RequestReceived has a useful debug representation.
    119        """
    120        e = h2.events.RequestReceived()
    121        e.stream_id = 5
    122        e.headers = self.example_request_headers
    123 
    124        assert repr(e) == (
    125            "<RequestReceived stream_id:5, headers:["
    126            "(':authority', 'example.com'), "
    127            "(':path', '/'), "
    128            "(':scheme', 'https'), "
    129            "(':method', 'GET')]>"
    130        )
    131 
    132    def test_responsereceived_repr(self):
    133        """
    134        ResponseReceived has a useful debug representation.
    135        """
    136        e = h2.events.ResponseReceived()
    137        e.stream_id = 500
    138        e.headers = self.example_response_headers
    139 
    140        assert repr(e) == (
    141            "<ResponseReceived stream_id:500, headers:["
    142            "(':status', '200'), "
    143            "('server', 'fake-serv/0.1.0')]>"
    144        )
    145 
    146    def test_trailersreceived_repr(self):
    147        """
    148        TrailersReceived has a useful debug representation.
    149        """
    150        e = h2.events.TrailersReceived()
    151        e.stream_id = 62
    152        e.headers = self.example_response_headers
    153 
    154        assert repr(e) == (
    155            "<TrailersReceived stream_id:62, headers:["
    156            "(':status', '200'), "
    157            "('server', 'fake-serv/0.1.0')]>"
    158        )
    159 
    160    def test_informationalresponsereceived_repr(self):
    161        """
    162        InformationalResponseReceived has a useful debug representation.
    163        """
    164        e = h2.events.InformationalResponseReceived()
    165        e.stream_id = 62
    166        e.headers = self.example_informational_headers
    167 
    168        assert repr(e) == (
    169            "<InformationalResponseReceived stream_id:62, headers:["
    170            "(':status', '100'), "
    171            "('server', 'fake-serv/0.1.0')]>"
    172        )
    173 
    174    def test_datareceived_repr(self):
    175        """
    176        DataReceived has a useful debug representation.
    177        """
    178        e = h2.events.DataReceived()
    179        e.stream_id = 888
    180        e.data = b"abcdefghijklmnopqrstuvwxyz"
    181        e.flow_controlled_length = 88
    182 
    183        assert repr(e) == (
    184            "<DataReceived stream_id:888, flow_controlled_length:88, "
    185            "data:6162636465666768696a6b6c6d6e6f7071727374>"
    186        )
    187 
    188    def test_windowupdated_repr(self):
    189        """
    190        WindowUpdated has a useful debug representation.
    191        """
    192        e = h2.events.WindowUpdated()
    193        e.stream_id = 0
    194        e.delta = 2**16
    195 
    196        assert repr(e) == "<WindowUpdated stream_id:0, delta:65536>"
    197 
    198    def test_remotesettingschanged_repr(self):
    199        """
    200        RemoteSettingsChanged has a useful debug representation.
    201        """
    202        e = h2.events.RemoteSettingsChanged()
    203        e.changed_settings = {
    204            h2.settings.SettingCodes.INITIAL_WINDOW_SIZE:
    205                h2.settings.ChangedSetting(
    206                    h2.settings.SettingCodes.INITIAL_WINDOW_SIZE, 2**16, 2**15
    207                ),
    208        }
    209 
    210        assert repr(e) == (
    211            "<RemoteSettingsChanged changed_settings:{ChangedSetting("
    212            "setting=SettingCodes.INITIAL_WINDOW_SIZE, original_value=65536, "
    213            "new_value=32768)}>"
    214        )
    215 
    216    def test_pingreceived_repr(self):
    217        """
    218        PingReceived has a useful debug representation.
    219        """
    220        e = h2.events.PingReceived()
    221        e.ping_data = b'abcdefgh'
    222 
    223        assert repr(e) == "<PingReceived ping_data:6162636465666768>"
    224 
    225    def test_pingackreceived_repr(self):
    226        """
    227        PingAckReceived has a useful debug representation.
    228        """
    229        e = h2.events.PingAckReceived()
    230        e.ping_data = b'abcdefgh'
    231 
    232        assert repr(e) == "<PingAckReceived ping_data:6162636465666768>"
    233 
    234    def test_streamended_repr(self):
    235        """
    236        StreamEnded has a useful debug representation.
    237        """
    238        e = h2.events.StreamEnded()
    239        e.stream_id = 99
    240 
    241        assert repr(e) == "<StreamEnded stream_id:99>"
    242 
    243    def test_streamreset_repr(self):
    244        """
    245        StreamEnded has a useful debug representation.
    246        """
    247        e = h2.events.StreamReset()
    248        e.stream_id = 919
    249        e.error_code = h2.errors.ErrorCodes.ENHANCE_YOUR_CALM
    250        e.remote_reset = False
    251 
    252        assert repr(e) == (
    253            "<StreamReset stream_id:919, "
    254            "error_code:ErrorCodes.ENHANCE_YOUR_CALM, remote_reset:False>"
    255        )
    256 
    257    def test_pushedstreamreceived_repr(self):
    258        """
    259        PushedStreamReceived has a useful debug representation.
    260        """
    261        e = h2.events.PushedStreamReceived()
    262        e.pushed_stream_id = 50
    263        e.parent_stream_id = 11
    264        e.headers = self.example_request_headers
    265 
    266        assert repr(e) == (
    267            "<PushedStreamReceived pushed_stream_id:50, parent_stream_id:11, "
    268            "headers:["
    269            "(':authority', 'example.com'), "
    270            "(':path', '/'), "
    271            "(':scheme', 'https'), "
    272            "(':method', 'GET')]>"
    273        )
    274 
    275    def test_settingsacknowledged_repr(self):
    276        """
    277        SettingsAcknowledged has a useful debug representation.
    278        """
    279        e = h2.events.SettingsAcknowledged()
    280        e.changed_settings = {
    281            h2.settings.SettingCodes.INITIAL_WINDOW_SIZE:
    282                h2.settings.ChangedSetting(
    283                    h2.settings.SettingCodes.INITIAL_WINDOW_SIZE, 2**16, 2**15
    284                ),
    285        }
    286 
    287        assert repr(e) == (
    288            "<SettingsAcknowledged changed_settings:{ChangedSetting("
    289            "setting=SettingCodes.INITIAL_WINDOW_SIZE, original_value=65536, "
    290            "new_value=32768)}>"
    291        )
    292 
    293    def test_priorityupdated_repr(self):
    294        """
    295        PriorityUpdated has a useful debug representation.
    296        """
    297        e = h2.events.PriorityUpdated()
    298        e.stream_id = 87
    299        e.weight = 32
    300        e.depends_on = 8
    301        e.exclusive = True
    302 
    303        assert repr(e) == (
    304            "<PriorityUpdated stream_id:87, weight:32, depends_on:8, "
    305            "exclusive:True>"
    306        )
    307 
    308    @pytest.mark.parametrize("additional_data,data_repr", [
    309        (None, "None"),
    310        (b'some data', "736f6d652064617461")
    311    ])
    312    def test_connectionterminated_repr(self, additional_data, data_repr):
    313        """
    314        ConnectionTerminated has a useful debug representation.
    315        """
    316        e = h2.events.ConnectionTerminated()
    317        e.error_code = h2.errors.ErrorCodes.INADEQUATE_SECURITY
    318        e.last_stream_id = 33
    319        e.additional_data = additional_data
    320 
    321        assert repr(e) == (
    322            "<ConnectionTerminated error_code:ErrorCodes.INADEQUATE_SECURITY, "
    323            "last_stream_id:33, additional_data:%s>" % data_repr
    324        )
    325 
    326    def test_alternativeserviceavailable_repr(self):
    327        """
    328        AlternativeServiceAvailable has a useful debug representation.
    329        """
    330        e = h2.events.AlternativeServiceAvailable()
    331        e.origin = b"example.com"
    332        e.field_value = b'h2=":8000"; ma=60'
    333 
    334        assert repr(e) == (
    335            '<AlternativeServiceAvailable origin:example.com, '
    336            'field_value:h2=":8000"; ma=60>'
    337        )
    338 
    339    def test_unknownframereceived_repr(self):
    340        """
    341        UnknownFrameReceived has a useful debug representation.
    342        """
    343        e = h2.events.UnknownFrameReceived()
    344        assert repr(e) == '<UnknownFrameReceived>'
    345 
    346 
    347 def all_events():
    348    """
    349    Generates all the classes (i.e., events) defined in h2.events.
    350    """
    351    for _, obj in inspect.getmembers(sys.modules['h2.events']):
    352 
    353        # We are only interested in objects that are defined in h2.events;
    354        # objects that are imported from other modules are not of interest.
    355        if hasattr(obj, '__module__') and (obj.__module__ != 'h2.events'):
    356            continue
    357 
    358        if inspect.isclass(obj):
    359            yield obj
    360 
    361 
    362 @pytest.mark.parametrize('event', all_events())
    363 def test_all_events_subclass_from_event(event):
    364    """
    365    Every event defined in h2.events subclasses from h2.events.Event.
    366    """
    367    assert (event is h2.events.Event) or issubclass(event, h2.events.Event)