Home | History | Annotate | Download | only in test
      1 #!/usr/bin/env python
      2 #
      3 # Copyright 2012, Google Inc.
      4 # All rights reserved.
      5 #
      6 # Redistribution and use in source and binary forms, with or without
      7 # modification, are permitted provided that the following conditions are
      8 # met:
      9 #
     10 #     * Redistributions of source code must retain the above copyright
     11 # notice, this list of conditions and the following disclaimer.
     12 #     * Redistributions in binary form must reproduce the above
     13 # copyright notice, this list of conditions and the following disclaimer
     14 # in the documentation and/or other materials provided with the
     15 # distribution.
     16 #     * Neither the name of Google Inc. nor the names of its
     17 # contributors may be used to endorse or promote products derived from
     18 # this software without specific prior written permission.
     19 #
     20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     23 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     24 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     25 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     26 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     30 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31 
     32 
     33 """Tests for handshake module."""
     34 
     35 
     36 import unittest
     37 
     38 import set_sys_path  # Update sys.path to locate mod_pywebsocket module.
     39 
     40 from mod_pywebsocket.common import ExtensionParameter
     41 from mod_pywebsocket.common import ExtensionParsingException
     42 from mod_pywebsocket.common import format_extensions
     43 from mod_pywebsocket.common import parse_extensions
     44 from mod_pywebsocket.handshake._base import HandshakeException
     45 from mod_pywebsocket.handshake._base import validate_subprotocol
     46 
     47 
     48 class HandshakerTest(unittest.TestCase):
     49     """A unittest for handshake module."""
     50 
     51     def test_validate_subprotocol(self):
     52         # should succeed.
     53         validate_subprotocol('sample', hixie=True)
     54         validate_subprotocol('Sample', hixie=True)
     55         validate_subprotocol('sample\x7eprotocol', hixie=True)
     56         validate_subprotocol('sample\x20protocol', hixie=True)
     57         validate_subprotocol('sample', hixie=False)
     58         validate_subprotocol('Sample', hixie=False)
     59         validate_subprotocol('sample\x7eprotocol', hixie=False)
     60 
     61         # should fail.
     62         self.assertRaises(HandshakeException,
     63                           validate_subprotocol,
     64                           '',
     65                           hixie=True)
     66         self.assertRaises(HandshakeException,
     67                           validate_subprotocol,
     68                           'sample\x19protocol',
     69                           hixie=True)
     70         self.assertRaises(HandshakeException,
     71                           validate_subprotocol,
     72                           'sample\x7fprotocol',
     73                           hixie=True)
     74         self.assertRaises(HandshakeException,
     75                           validate_subprotocol,
     76                           # "Japan" in Japanese
     77                           u'\u65e5\u672c',
     78                           hixie=True)
     79         self.assertRaises(HandshakeException,
     80                           validate_subprotocol,
     81                           '',
     82                           hixie=False)
     83         self.assertRaises(HandshakeException,
     84                           validate_subprotocol,
     85                           'sample\x09protocol',
     86                           hixie=False)
     87         self.assertRaises(HandshakeException,
     88                           validate_subprotocol,
     89                           'sample\x19protocol',
     90                           hixie=False)
     91         self.assertRaises(HandshakeException,
     92                           validate_subprotocol,
     93                           'sample\x20protocol',
     94                           hixie=False)
     95         self.assertRaises(HandshakeException,
     96                           validate_subprotocol,
     97                           'sample\x7fprotocol',
     98                           hixie=False)
     99         self.assertRaises(HandshakeException,
    100                           validate_subprotocol,
    101                           # "Japan" in Japanese
    102                           u'\u65e5\u672c',
    103                           hixie=False)
    104 
    105 
    106 _TEST_TOKEN_EXTENSION_DATA = [
    107     ('foo', [('foo', [])]),
    108     ('foo; bar', [('foo', [('bar', None)])]),
    109     ('foo; bar=baz', [('foo', [('bar', 'baz')])]),
    110     ('foo; bar=baz; car=cdr', [('foo', [('bar', 'baz'), ('car', 'cdr')])]),
    111     ('foo; bar=baz, car; cdr',
    112      [('foo', [('bar', 'baz')]), ('car', [('cdr', None)])]),
    113     ('a, b, c, d',
    114      [('a', []), ('b', []), ('c', []), ('d', [])]),
    115     ]
    116 
    117 
    118 _TEST_QUOTED_EXTENSION_DATA = [
    119     ('foo; bar=""', [('foo', [('bar', '')])]),
    120     ('foo; bar=" baz "', [('foo', [('bar', ' baz ')])]),
    121     ('foo; bar=",baz;"', [('foo', [('bar', ',baz;')])]),
    122     ('foo; bar="\\\r\\\nbaz"', [('foo', [('bar', '\r\nbaz')])]),
    123     ('foo; bar="\\"baz"', [('foo', [('bar', '"baz')])]),
    124     ('foo; bar="\xbbbaz"', [('foo', [('bar', '\xbbbaz')])]),
    125     ]
    126 
    127 
    128 _TEST_REDUNDANT_TOKEN_EXTENSION_DATA = [
    129     ('foo \t ', [('foo', [])]),
    130     ('foo; \r\n bar', [('foo', [('bar', None)])]),
    131     ('foo; bar=\r\n \r\n baz', [('foo', [('bar', 'baz')])]),
    132     ('foo ;bar = baz ', [('foo', [('bar', 'baz')])]),
    133     ('foo,bar,,baz', [('foo', []), ('bar', []), ('baz', [])]),
    134     ]
    135 
    136 
    137 _TEST_REDUNDANT_QUOTED_EXTENSION_DATA = [
    138     ('foo; bar="\r\n \r\n baz"', [('foo', [('bar', '  baz')])]),
    139     ]
    140 
    141 
    142 class ExtensionsParserTest(unittest.TestCase):
    143 
    144     def _verify_extension_list(self, expected_list, actual_list):
    145         """Verifies that ExtensionParameter objects in actual_list have the
    146         same members as extension definitions in expected_list. Extension
    147         definition used in this test is a pair of an extension name and a
    148         parameter dictionary.
    149         """
    150 
    151         self.assertEqual(len(expected_list), len(actual_list))
    152         for expected, actual in zip(expected_list, actual_list):
    153             (name, parameters) = expected
    154             self.assertEqual(name, actual._name)
    155             self.assertEqual(parameters, actual._parameters)
    156 
    157     def test_parse(self):
    158         for formatted_string, definition in _TEST_TOKEN_EXTENSION_DATA:
    159             self._verify_extension_list(
    160                 definition, parse_extensions(formatted_string,
    161                                              allow_quoted_string=False))
    162 
    163         for formatted_string, unused_definition in _TEST_QUOTED_EXTENSION_DATA:
    164             self.assertRaises(
    165                 ExtensionParsingException, parse_extensions,
    166                 formatted_string, False)
    167 
    168     def test_parse_with_allow_quoted_string(self):
    169         for formatted_string, definition in _TEST_TOKEN_EXTENSION_DATA:
    170             self._verify_extension_list(
    171                 definition, parse_extensions(formatted_string,
    172                                              allow_quoted_string=True))
    173 
    174         for formatted_string, definition in _TEST_QUOTED_EXTENSION_DATA:
    175             self._verify_extension_list(
    176                 definition, parse_extensions(formatted_string,
    177                                              allow_quoted_string=True))
    178 
    179     def test_parse_redundant_data(self):
    180         for (formatted_string,
    181              definition) in _TEST_REDUNDANT_TOKEN_EXTENSION_DATA:
    182             self._verify_extension_list(
    183                 definition, parse_extensions(formatted_string,
    184                                              allow_quoted_string=False))
    185 
    186         for (formatted_string,
    187              definition) in _TEST_REDUNDANT_QUOTED_EXTENSION_DATA:
    188             self.assertRaises(
    189                 ExtensionParsingException, parse_extensions,
    190                 formatted_string, False)
    191 
    192     def test_parse_redundant_data_with_allow_quoted_string(self):
    193         for (formatted_string,
    194              definition) in _TEST_REDUNDANT_TOKEN_EXTENSION_DATA:
    195             self._verify_extension_list(
    196                 definition, parse_extensions(formatted_string,
    197                                              allow_quoted_string=True))
    198 
    199         for (formatted_string,
    200              definition) in _TEST_REDUNDANT_QUOTED_EXTENSION_DATA:
    201             self._verify_extension_list(
    202                 definition, parse_extensions(formatted_string,
    203                                              allow_quoted_string=True))
    204 
    205     def test_parse_bad_data(self):
    206         _TEST_BAD_EXTENSION_DATA = [
    207             ('foo; ; '),
    208             ('foo; a a'),
    209             ('foo foo'),
    210             (',,,'),
    211             ('foo; bar='),
    212             ('foo; bar="hoge'),
    213             ('foo; bar="a\r"'),
    214             ('foo; bar="\\\xff"'),
    215             ('foo; bar=\ra'),
    216             ]
    217 
    218         for formatted_string in _TEST_BAD_EXTENSION_DATA:
    219             self.assertRaises(
    220                 ExtensionParsingException, parse_extensions, formatted_string)
    221 
    222 
    223 class FormatExtensionsTest(unittest.TestCase):
    224 
    225     def test_format_extensions(self):
    226         for formatted_string, definitions in _TEST_TOKEN_EXTENSION_DATA:
    227             extensions = []
    228             for definition in definitions:
    229                 (name, parameters) = definition
    230                 extension = ExtensionParameter(name)
    231                 extension._parameters = parameters
    232                 extensions.append(extension)
    233             self.assertEqual(
    234                 formatted_string, format_extensions(extensions))
    235 
    236 
    237 if __name__ == '__main__':
    238     unittest.main()
    239 
    240 
    241 # vi:sts=4 sw=4 et
    242