Home | History | Annotate | Download | only in test
      1 # Copyright 2011, Google Inc.
      2 # All rights reserved.
      3 #
      4 # Redistribution and use in source and binary forms, with or without
      5 # modification, are permitted provided that the following conditions are
      6 # met:
      7 #
      8 #     * Redistributions of source code must retain the above copyright
      9 # notice, this list of conditions and the following disclaimer.
     10 #     * Redistributions in binary form must reproduce the above
     11 # copyright notice, this list of conditions and the following disclaimer
     12 # in the documentation and/or other materials provided with the
     13 # distribution.
     14 #     * Neither the name of Google Inc. nor the names of its
     15 # contributors may be used to endorse or promote products derived from
     16 # this software without specific prior written permission.
     17 #
     18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 
     31 """Mocks for testing.
     32 """
     33 
     34 
     35 import Queue
     36 import threading
     37 
     38 from mod_pywebsocket import common
     39 from mod_pywebsocket.stream import StreamHixie75
     40 
     41 
     42 class _MockConnBase(object):
     43     """Base class of mocks for mod_python.apache.mp_conn.
     44 
     45     This enables tests to check what is written to a (mock) mp_conn.
     46     """
     47 
     48     def __init__(self):
     49         self._write_data = []
     50         self.remote_addr = 'fake_address'
     51 
     52     def write(self, data):
     53         """Override mod_python.apache.mp_conn.write."""
     54 
     55         self._write_data.append(data)
     56 
     57     def written_data(self):
     58         """Get bytes written to this mock."""
     59 
     60         return ''.join(self._write_data)
     61 
     62 
     63 class MockConn(_MockConnBase):
     64     """Mock for mod_python.apache.mp_conn.
     65 
     66     This enables tests to specify what should be read from a (mock) mp_conn as
     67     well as to check what is written to it.
     68     """
     69 
     70     def __init__(self, read_data):
     71         """Constructs an instance.
     72 
     73         Args:
     74             read_data: bytes that should be returned when read* methods are
     75             called.
     76         """
     77 
     78         _MockConnBase.__init__(self)
     79         self._read_data = read_data
     80         self._read_pos = 0
     81 
     82     def readline(self):
     83         """Override mod_python.apache.mp_conn.readline."""
     84 
     85         if self._read_pos >= len(self._read_data):
     86             return ''
     87         end_index = self._read_data.find('\n', self._read_pos) + 1
     88         if not end_index:
     89             end_index = len(self._read_data)
     90         return self._read_up_to(end_index)
     91 
     92     def read(self, length):
     93         """Override mod_python.apache.mp_conn.read."""
     94 
     95         if self._read_pos >= len(self._read_data):
     96             return ''
     97         end_index = min(len(self._read_data), self._read_pos + length)
     98         return self._read_up_to(end_index)
     99 
    100     def _read_up_to(self, end_index):
    101         line = self._read_data[self._read_pos:end_index]
    102         self._read_pos = end_index
    103         return line
    104 
    105 
    106 class MockBlockingConn(_MockConnBase):
    107     """Blocking mock for mod_python.apache.mp_conn.
    108 
    109     This enables tests to specify what should be read from a (mock) mp_conn as
    110     well as to check what is written to it.
    111     Callers of read* methods will block if there is no bytes available.
    112     """
    113 
    114     def __init__(self):
    115         _MockConnBase.__init__(self)
    116         self._queue = Queue.Queue()
    117 
    118     def readline(self):
    119         """Override mod_python.apache.mp_conn.readline."""
    120         line = ''
    121         while True:
    122             c = self._queue.get()
    123             line += c
    124             if c == '\n':
    125                 return line
    126 
    127     def read(self, length):
    128         """Override mod_python.apache.mp_conn.read."""
    129 
    130         data = ''
    131         for unused in range(length):
    132             data += self._queue.get()
    133         return data
    134 
    135     def put_bytes(self, bytes):
    136         """Put bytes to be read from this mock.
    137 
    138         Args:
    139             bytes: bytes to be read.
    140         """
    141 
    142         for byte in bytes:
    143             self._queue.put(byte)
    144 
    145 
    146 class MockTable(dict):
    147     """Mock table.
    148 
    149     This mimics mod_python mp_table. Note that only the methods used by
    150     tests are overridden.
    151     """
    152 
    153     def __init__(self, copy_from={}):
    154         if isinstance(copy_from, dict):
    155             copy_from = copy_from.items()
    156         for key, value in copy_from:
    157             self.__setitem__(key, value)
    158 
    159     def __getitem__(self, key):
    160         return super(MockTable, self).__getitem__(key.lower())
    161 
    162     def __setitem__(self, key, value):
    163         super(MockTable, self).__setitem__(key.lower(), value)
    164 
    165     def get(self, key, def_value=None):
    166         return super(MockTable, self).get(key.lower(), def_value)
    167 
    168 
    169 class MockRequest(object):
    170     """Mock request.
    171 
    172     This mimics mod_python request.
    173     """
    174 
    175     def __init__(self, uri=None, headers_in={}, connection=None, method='GET',
    176                  is_https=False):
    177         """Construct an instance.
    178 
    179         Arguments:
    180             uri: URI of the request.
    181             headers_in: Request headers.
    182             connection: Connection used for the request.
    183             method: request method.
    184             is_https: Whether this request is over SSL.
    185 
    186         See the document of mod_python Request for details.
    187         """
    188         self.uri = uri
    189         self.connection = connection
    190         self.method = method
    191         self.headers_in = MockTable(headers_in)
    192         # self.is_https_ needs to be accessible from tests.  To avoid name
    193         # conflict with self.is_https(), it is named as such.
    194         self.is_https_ = is_https
    195         self.ws_stream = StreamHixie75(self, True)
    196         self.ws_close_code = None
    197         self.ws_close_reason = None
    198         self.ws_version = common.VERSION_HYBI00
    199         self.ws_deflate = False
    200 
    201         self.drain_received_data_called = False
    202 
    203     def is_https(self):
    204         """Return whether this request is over SSL."""
    205         return self.is_https_
    206 
    207     def _drain_received_data(self):
    208         self.drain_received_data_called = True
    209 
    210 
    211 class MockDispatcher(object):
    212     """Mock for dispatch.Dispatcher."""
    213 
    214     def __init__(self):
    215         self.do_extra_handshake_called = False
    216 
    217     def do_extra_handshake(self, conn_context):
    218         self.do_extra_handshake_called = True
    219 
    220     def transfer_data(self, conn_context):
    221         pass
    222 
    223 
    224 # vi:sts=4 sw=4 et
    225