• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
35import Queue
36import threading
37
38from mod_pywebsocket import common
39from mod_pywebsocket.stream import StreamHixie75
40
41
42class _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
63class 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
106class 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
146class 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
169class 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
211class 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