Statistics
| Branch: | Tag: | Revision:

root / test / py / ganeti.http_unittest.py @ 560ef132

History | View | Annotate | Download (26.2 kB)

1 a0638838 Oleksiy Mishchenko
#!/usr/bin/python
2 a0638838 Oleksiy Mishchenko
#
3 a0638838 Oleksiy Mishchenko
4 a0638838 Oleksiy Mishchenko
# Copyright (C) 2007, 2008 Google Inc.
5 a0638838 Oleksiy Mishchenko
#
6 a0638838 Oleksiy Mishchenko
# This program is free software; you can redistribute it and/or modify
7 a0638838 Oleksiy Mishchenko
# it under the terms of the GNU General Public License as published by
8 a0638838 Oleksiy Mishchenko
# the Free Software Foundation; either version 2 of the License, or
9 a0638838 Oleksiy Mishchenko
# (at your option) any later version.
10 a0638838 Oleksiy Mishchenko
#
11 a0638838 Oleksiy Mishchenko
# This program is distributed in the hope that it will be useful, but
12 a0638838 Oleksiy Mishchenko
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a0638838 Oleksiy Mishchenko
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a0638838 Oleksiy Mishchenko
# General Public License for more details.
15 a0638838 Oleksiy Mishchenko
#
16 a0638838 Oleksiy Mishchenko
# You should have received a copy of the GNU General Public License
17 a0638838 Oleksiy Mishchenko
# along with this program; if not, write to the Free Software
18 a0638838 Oleksiy Mishchenko
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a0638838 Oleksiy Mishchenko
# 02110-1301, USA.
20 a0638838 Oleksiy Mishchenko
21 a0638838 Oleksiy Mishchenko
22 a0638838 Oleksiy Mishchenko
"""Script for unittesting the http module"""
23 a0638838 Oleksiy Mishchenko
24 a0638838 Oleksiy Mishchenko
25 a0638838 Oleksiy Mishchenko
import os
26 a0638838 Oleksiy Mishchenko
import unittest
27 a0638838 Oleksiy Mishchenko
import time
28 a8950eb7 Michael Hanselmann
import tempfile
29 abbf2cd9 Michael Hanselmann
import pycurl
30 abbf2cd9 Michael Hanselmann
import itertools
31 abbf2cd9 Michael Hanselmann
import threading
32 2287b920 Michael Hanselmann
from cStringIO import StringIO
33 a0638838 Oleksiy Mishchenko
34 a0638838 Oleksiy Mishchenko
from ganeti import http
35 abbf2cd9 Michael Hanselmann
from ganeti import compat
36 a0638838 Oleksiy Mishchenko
37 f30ca1e6 Michael Hanselmann
import ganeti.http.server
38 f30ca1e6 Michael Hanselmann
import ganeti.http.client
39 bf9bd8dd Michael Hanselmann
import ganeti.http.auth
40 a0638838 Oleksiy Mishchenko
41 25231ec5 Michael Hanselmann
import testutils
42 25231ec5 Michael Hanselmann
43 f30ca1e6 Michael Hanselmann
44 f30ca1e6 Michael Hanselmann
class TestStartLines(unittest.TestCase):
45 f30ca1e6 Michael Hanselmann
  """Test cases for start line classes"""
46 f30ca1e6 Michael Hanselmann
47 f30ca1e6 Michael Hanselmann
  def testClientToServerStartLine(self):
48 f30ca1e6 Michael Hanselmann
    """Test client to server start line (HTTP request)"""
49 f30ca1e6 Michael Hanselmann
    start_line = http.HttpClientToServerStartLine("GET", "/", "HTTP/1.1")
50 f30ca1e6 Michael Hanselmann
    self.assertEqual(str(start_line), "GET / HTTP/1.1")
51 f30ca1e6 Michael Hanselmann
52 f30ca1e6 Michael Hanselmann
  def testServerToClientStartLine(self):
53 f30ca1e6 Michael Hanselmann
    """Test server to client start line (HTTP response)"""
54 f30ca1e6 Michael Hanselmann
    start_line = http.HttpServerToClientStartLine("HTTP/1.1", 200, "OK")
55 f30ca1e6 Michael Hanselmann
    self.assertEqual(str(start_line), "HTTP/1.1 200 OK")
56 f30ca1e6 Michael Hanselmann
57 f30ca1e6 Michael Hanselmann
58 f30ca1e6 Michael Hanselmann
class TestMisc(unittest.TestCase):
59 f30ca1e6 Michael Hanselmann
  """Miscellaneous tests"""
60 f30ca1e6 Michael Hanselmann
61 f30ca1e6 Michael Hanselmann
  def _TestDateTimeHeader(self, gmnow, expected):
62 f30ca1e6 Michael Hanselmann
    self.assertEqual(http.server._DateTimeHeader(gmnow=gmnow), expected)
63 f30ca1e6 Michael Hanselmann
64 f30ca1e6 Michael Hanselmann
  def testDateTimeHeader(self):
65 f30ca1e6 Michael Hanselmann
    """Test ganeti.http._DateTimeHeader"""
66 f30ca1e6 Michael Hanselmann
    self._TestDateTimeHeader((2008, 1, 2, 3, 4, 5, 3, 0, 0),
67 f30ca1e6 Michael Hanselmann
                             "Thu, 02 Jan 2008 03:04:05 GMT")
68 f30ca1e6 Michael Hanselmann
    self._TestDateTimeHeader((2008, 1, 1, 0, 0, 0, 0, 0, 0),
69 f30ca1e6 Michael Hanselmann
                             "Mon, 01 Jan 2008 00:00:00 GMT")
70 f30ca1e6 Michael Hanselmann
    self._TestDateTimeHeader((2008, 12, 31, 0, 0, 0, 0, 0, 0),
71 f30ca1e6 Michael Hanselmann
                             "Mon, 31 Dec 2008 00:00:00 GMT")
72 f30ca1e6 Michael Hanselmann
    self._TestDateTimeHeader((2008, 12, 31, 23, 59, 59, 0, 0, 0),
73 f30ca1e6 Michael Hanselmann
                             "Mon, 31 Dec 2008 23:59:59 GMT")
74 f30ca1e6 Michael Hanselmann
    self._TestDateTimeHeader((2008, 12, 31, 0, 0, 0, 6, 0, 0),
75 f30ca1e6 Michael Hanselmann
                             "Sun, 31 Dec 2008 00:00:00 GMT")
76 f30ca1e6 Michael Hanselmann
77 f30ca1e6 Michael Hanselmann
  def testHttpServerRequest(self):
78 f30ca1e6 Michael Hanselmann
    """Test ganeti.http.server._HttpServerRequest"""
79 a8950eb7 Michael Hanselmann
    server_request = http.server._HttpServerRequest("GET", "/", None, None)
80 f30ca1e6 Michael Hanselmann
81 f30ca1e6 Michael Hanselmann
    # These are expected by users of the HTTP server
82 f30ca1e6 Michael Hanselmann
    self.assert_(hasattr(server_request, "request_method"))
83 f30ca1e6 Michael Hanselmann
    self.assert_(hasattr(server_request, "request_path"))
84 f30ca1e6 Michael Hanselmann
    self.assert_(hasattr(server_request, "request_headers"))
85 f30ca1e6 Michael Hanselmann
    self.assert_(hasattr(server_request, "request_body"))
86 f30ca1e6 Michael Hanselmann
    self.assert_(isinstance(server_request.resp_headers, dict))
87 68fa9caf Michael Hanselmann
    self.assert_(hasattr(server_request, "private"))
88 f30ca1e6 Michael Hanselmann
89 f30ca1e6 Michael Hanselmann
  def testServerSizeLimits(self):
90 f30ca1e6 Michael Hanselmann
    """Test HTTP server size limits"""
91 f30ca1e6 Michael Hanselmann
    message_reader_class = http.server._HttpClientToServerMessageReader
92 f30ca1e6 Michael Hanselmann
    self.assert_(message_reader_class.START_LINE_LENGTH_MAX > 0)
93 f30ca1e6 Michael Hanselmann
    self.assert_(message_reader_class.HEADER_LENGTH_MAX > 0)
94 f30ca1e6 Michael Hanselmann
95 a8950eb7 Michael Hanselmann
  def testFormatAuthHeader(self):
96 a8950eb7 Michael Hanselmann
    self.assertEqual(http.auth._FormatAuthHeader("Basic", {}),
97 a8950eb7 Michael Hanselmann
                     "Basic")
98 a8950eb7 Michael Hanselmann
    self.assertEqual(http.auth._FormatAuthHeader("Basic", { "foo": "bar", }),
99 a8950eb7 Michael Hanselmann
                     "Basic foo=bar")
100 a8950eb7 Michael Hanselmann
    self.assertEqual(http.auth._FormatAuthHeader("Basic", { "foo": "", }),
101 a8950eb7 Michael Hanselmann
                     "Basic foo=\"\"")
102 a8950eb7 Michael Hanselmann
    self.assertEqual(http.auth._FormatAuthHeader("Basic", { "foo": "x,y", }),
103 a8950eb7 Michael Hanselmann
                     "Basic foo=\"x,y\"")
104 a8950eb7 Michael Hanselmann
    params = {
105 a8950eb7 Michael Hanselmann
      "foo": "x,y",
106 a8950eb7 Michael Hanselmann
      "realm": "secure",
107 a8950eb7 Michael Hanselmann
      }
108 a8950eb7 Michael Hanselmann
    # It's a dict whose order isn't guaranteed, hence checking a list
109 a8950eb7 Michael Hanselmann
    self.assert_(http.auth._FormatAuthHeader("Digest", params) in
110 a8950eb7 Michael Hanselmann
                 ("Digest foo=\"x,y\" realm=secure",
111 a8950eb7 Michael Hanselmann
                  "Digest realm=secure foo=\"x,y\""))
112 a8950eb7 Michael Hanselmann
113 a0638838 Oleksiy Mishchenko
114 bf9bd8dd Michael Hanselmann
class _FakeRequestAuth(http.auth.HttpServerRequestAuthentication):
115 a8950eb7 Michael Hanselmann
  def __init__(self, realm, authreq, authenticate_fn):
116 bf9bd8dd Michael Hanselmann
    http.auth.HttpServerRequestAuthentication.__init__(self)
117 bf9bd8dd Michael Hanselmann
118 bf9bd8dd Michael Hanselmann
    self.realm = realm
119 a8950eb7 Michael Hanselmann
    self.authreq = authreq
120 a8950eb7 Michael Hanselmann
    self.authenticate_fn = authenticate_fn
121 a8950eb7 Michael Hanselmann
122 a8950eb7 Michael Hanselmann
  def AuthenticationRequired(self, req):
123 a8950eb7 Michael Hanselmann
    return self.authreq
124 bf9bd8dd Michael Hanselmann
125 bf9bd8dd Michael Hanselmann
  def GetAuthRealm(self, req):
126 bf9bd8dd Michael Hanselmann
    return self.realm
127 bf9bd8dd Michael Hanselmann
128 a8950eb7 Michael Hanselmann
  def Authenticate(self, *args):
129 a8950eb7 Michael Hanselmann
    if self.authenticate_fn:
130 a8950eb7 Michael Hanselmann
      return self.authenticate_fn(*args)
131 a8950eb7 Michael Hanselmann
    raise NotImplementedError()
132 a8950eb7 Michael Hanselmann
133 bf9bd8dd Michael Hanselmann
134 bf9bd8dd Michael Hanselmann
class TestAuth(unittest.TestCase):
135 bf9bd8dd Michael Hanselmann
  """Authentication tests"""
136 bf9bd8dd Michael Hanselmann
137 bf9bd8dd Michael Hanselmann
  hsra = http.auth.HttpServerRequestAuthentication
138 bf9bd8dd Michael Hanselmann
139 bf9bd8dd Michael Hanselmann
  def testConstants(self):
140 a8950eb7 Michael Hanselmann
    for scheme in [self.hsra._CLEARTEXT_SCHEME, self.hsra._HA1_SCHEME]:
141 a8950eb7 Michael Hanselmann
      self.assertEqual(scheme, scheme.upper())
142 a8950eb7 Michael Hanselmann
      self.assert_(scheme.startswith("{"))
143 a8950eb7 Michael Hanselmann
      self.assert_(scheme.endswith("}"))
144 bf9bd8dd Michael Hanselmann
145 bf9bd8dd Michael Hanselmann
  def _testVerifyBasicAuthPassword(self, realm, user, password, expected):
146 a8950eb7 Michael Hanselmann
    ra = _FakeRequestAuth(realm, False, None)
147 bf9bd8dd Michael Hanselmann
148 bf9bd8dd Michael Hanselmann
    return ra.VerifyBasicAuthPassword(None, user, password, expected)
149 bf9bd8dd Michael Hanselmann
150 bf9bd8dd Michael Hanselmann
  def testVerifyBasicAuthPassword(self):
151 bf9bd8dd Michael Hanselmann
    tvbap = self._testVerifyBasicAuthPassword
152 bf9bd8dd Michael Hanselmann
153 bf9bd8dd Michael Hanselmann
    good_pws = ["pw", "pw{", "pw}", "pw{}", "pw{x}y", "}pw",
154 bf9bd8dd Michael Hanselmann
                "0", "123", "foo...:xyz", "TeST"]
155 bf9bd8dd Michael Hanselmann
156 bf9bd8dd Michael Hanselmann
    for pw in good_pws:
157 bf9bd8dd Michael Hanselmann
      # Try cleartext passwords
158 bf9bd8dd Michael Hanselmann
      self.assert_(tvbap("abc", "user", pw, pw))
159 bf9bd8dd Michael Hanselmann
      self.assert_(tvbap("abc", "user", pw, "{cleartext}" + pw))
160 bf9bd8dd Michael Hanselmann
      self.assert_(tvbap("abc", "user", pw, "{ClearText}" + pw))
161 bf9bd8dd Michael Hanselmann
      self.assert_(tvbap("abc", "user", pw, "{CLEARTEXT}" + pw))
162 bf9bd8dd Michael Hanselmann
163 bf9bd8dd Michael Hanselmann
      # Try with invalid password
164 bf9bd8dd Michael Hanselmann
      self.failIf(tvbap("abc", "user", pw, "something"))
165 bf9bd8dd Michael Hanselmann
166 bf9bd8dd Michael Hanselmann
      # Try with invalid scheme
167 bf9bd8dd Michael Hanselmann
      self.failIf(tvbap("abc", "user", pw, "{000}" + pw))
168 bf9bd8dd Michael Hanselmann
      self.failIf(tvbap("abc", "user", pw, "{unk}" + pw))
169 bf9bd8dd Michael Hanselmann
      self.failIf(tvbap("abc", "user", pw, "{Unk}" + pw))
170 bf9bd8dd Michael Hanselmann
      self.failIf(tvbap("abc", "user", pw, "{UNK}" + pw))
171 bf9bd8dd Michael Hanselmann
172 bf9bd8dd Michael Hanselmann
    # Try with invalid scheme format
173 bf9bd8dd Michael Hanselmann
    self.failIf(tvbap("abc", "user", "pw", "{something"))
174 bf9bd8dd Michael Hanselmann
175 bf9bd8dd Michael Hanselmann
    # Hash is MD5("user:This is only a test:pw")
176 bf9bd8dd Michael Hanselmann
    self.assert_(tvbap("This is only a test", "user", "pw",
177 bf9bd8dd Michael Hanselmann
                       "{ha1}92ea58ae804481498c257b2f65561a17"))
178 bf9bd8dd Michael Hanselmann
    self.assert_(tvbap("This is only a test", "user", "pw",
179 bf9bd8dd Michael Hanselmann
                       "{HA1}92ea58ae804481498c257b2f65561a17"))
180 bf9bd8dd Michael Hanselmann
181 23ccba04 Michael Hanselmann
    self.failUnlessRaises(AssertionError, tvbap, None, "user", "pw",
182 23ccba04 Michael Hanselmann
                          "{HA1}92ea58ae804481498c257b2f65561a17")
183 bf9bd8dd Michael Hanselmann
    self.failIf(tvbap("Admin area", "user", "pw",
184 bf9bd8dd Michael Hanselmann
                      "{HA1}92ea58ae804481498c257b2f65561a17"))
185 bf9bd8dd Michael Hanselmann
    self.failIf(tvbap("This is only a test", "someone", "pw",
186 bf9bd8dd Michael Hanselmann
                      "{HA1}92ea58ae804481498c257b2f65561a17"))
187 bf9bd8dd Michael Hanselmann
    self.failIf(tvbap("This is only a test", "user", "something",
188 bf9bd8dd Michael Hanselmann
                      "{HA1}92ea58ae804481498c257b2f65561a17"))
189 bf9bd8dd Michael Hanselmann
190 bf9bd8dd Michael Hanselmann
191 a8950eb7 Michael Hanselmann
class _SimpleAuthenticator:
192 a8950eb7 Michael Hanselmann
  def __init__(self, user, password):
193 a8950eb7 Michael Hanselmann
    self.user = user
194 a8950eb7 Michael Hanselmann
    self.password = password
195 a8950eb7 Michael Hanselmann
    self.called = False
196 a8950eb7 Michael Hanselmann
197 a8950eb7 Michael Hanselmann
  def __call__(self, req, user, password):
198 a8950eb7 Michael Hanselmann
    self.called = True
199 a8950eb7 Michael Hanselmann
    return self.user == user and self.password == password
200 a8950eb7 Michael Hanselmann
201 a8950eb7 Michael Hanselmann
202 a8950eb7 Michael Hanselmann
class TestHttpServerRequestAuthentication(unittest.TestCase):
203 a8950eb7 Michael Hanselmann
  def testNoAuth(self):
204 a8950eb7 Michael Hanselmann
    req = http.server._HttpServerRequest("GET", "/", None, None)
205 a8950eb7 Michael Hanselmann
    _FakeRequestAuth("area1", False, None).PreHandleRequest(req)
206 a8950eb7 Michael Hanselmann
207 a8950eb7 Michael Hanselmann
  def testNoRealm(self):
208 a8950eb7 Michael Hanselmann
    headers = { http.HTTP_AUTHORIZATION: "", }
209 a8950eb7 Michael Hanselmann
    req = http.server._HttpServerRequest("GET", "/", headers, None)
210 a8950eb7 Michael Hanselmann
    ra = _FakeRequestAuth(None, False, None)
211 a8950eb7 Michael Hanselmann
    self.assertRaises(AssertionError, ra.PreHandleRequest, req)
212 a8950eb7 Michael Hanselmann
213 a8950eb7 Michael Hanselmann
  def testNoScheme(self):
214 a8950eb7 Michael Hanselmann
    headers = { http.HTTP_AUTHORIZATION: "", }
215 a8950eb7 Michael Hanselmann
    req = http.server._HttpServerRequest("GET", "/", headers, None)
216 a8950eb7 Michael Hanselmann
    ra = _FakeRequestAuth("area1", False, None)
217 a8950eb7 Michael Hanselmann
    self.assertRaises(http.HttpUnauthorized, ra.PreHandleRequest, req)
218 a8950eb7 Michael Hanselmann
219 a8950eb7 Michael Hanselmann
  def testUnknownScheme(self):
220 a8950eb7 Michael Hanselmann
    headers = { http.HTTP_AUTHORIZATION: "NewStyleAuth abc", }
221 a8950eb7 Michael Hanselmann
    req = http.server._HttpServerRequest("GET", "/", headers, None)
222 a8950eb7 Michael Hanselmann
    ra = _FakeRequestAuth("area1", False, None)
223 a8950eb7 Michael Hanselmann
    self.assertRaises(http.HttpUnauthorized, ra.PreHandleRequest, req)
224 a8950eb7 Michael Hanselmann
225 a8950eb7 Michael Hanselmann
  def testInvalidBase64(self):
226 a8950eb7 Michael Hanselmann
    headers = { http.HTTP_AUTHORIZATION: "Basic x_=_", }
227 a8950eb7 Michael Hanselmann
    req = http.server._HttpServerRequest("GET", "/", headers, None)
228 a8950eb7 Michael Hanselmann
    ra = _FakeRequestAuth("area1", False, None)
229 a8950eb7 Michael Hanselmann
    self.assertRaises(http.HttpUnauthorized, ra.PreHandleRequest, req)
230 a8950eb7 Michael Hanselmann
231 a8950eb7 Michael Hanselmann
  def testAuthForPublicResource(self):
232 a8950eb7 Michael Hanselmann
    headers = {
233 a8950eb7 Michael Hanselmann
      http.HTTP_AUTHORIZATION: "Basic %s" % ("foo".encode("base64").strip(), ),
234 a8950eb7 Michael Hanselmann
      }
235 a8950eb7 Michael Hanselmann
    req = http.server._HttpServerRequest("GET", "/", headers, None)
236 a8950eb7 Michael Hanselmann
    ra = _FakeRequestAuth("area1", False, None)
237 a8950eb7 Michael Hanselmann
    self.assertRaises(http.HttpUnauthorized, ra.PreHandleRequest, req)
238 a8950eb7 Michael Hanselmann
239 a8950eb7 Michael Hanselmann
  def testAuthForPublicResource(self):
240 a8950eb7 Michael Hanselmann
    headers = {
241 a8950eb7 Michael Hanselmann
      http.HTTP_AUTHORIZATION:
242 a8950eb7 Michael Hanselmann
        "Basic %s" % ("foo:bar".encode("base64").strip(), ),
243 a8950eb7 Michael Hanselmann
      }
244 a8950eb7 Michael Hanselmann
    req = http.server._HttpServerRequest("GET", "/", headers, None)
245 a8950eb7 Michael Hanselmann
    ac = _SimpleAuthenticator("foo", "bar")
246 a8950eb7 Michael Hanselmann
    ra = _FakeRequestAuth("area1", False, ac)
247 a8950eb7 Michael Hanselmann
    ra.PreHandleRequest(req)
248 a8950eb7 Michael Hanselmann
249 a8950eb7 Michael Hanselmann
    req = http.server._HttpServerRequest("GET", "/", headers, None)
250 a8950eb7 Michael Hanselmann
    ac = _SimpleAuthenticator("something", "else")
251 a8950eb7 Michael Hanselmann
    ra = _FakeRequestAuth("area1", False, ac)
252 a8950eb7 Michael Hanselmann
    self.assertRaises(http.HttpUnauthorized, ra.PreHandleRequest, req)
253 a8950eb7 Michael Hanselmann
254 a8950eb7 Michael Hanselmann
  def testInvalidRequestHeader(self):
255 a8950eb7 Michael Hanselmann
    checks = {
256 a8950eb7 Michael Hanselmann
      http.HttpUnauthorized: ["", "\t", "-", ".", "@", "<", ">", "Digest",
257 a8950eb7 Michael Hanselmann
                              "basic %s" % "foobar".encode("base64").strip()],
258 a8950eb7 Michael Hanselmann
      http.HttpBadRequest: ["Basic"],
259 a8950eb7 Michael Hanselmann
      }
260 a8950eb7 Michael Hanselmann
261 a8950eb7 Michael Hanselmann
    for exc, headers in checks.items():
262 a8950eb7 Michael Hanselmann
      for i in headers:
263 a8950eb7 Michael Hanselmann
        headers = { http.HTTP_AUTHORIZATION: i, }
264 a8950eb7 Michael Hanselmann
        req = http.server._HttpServerRequest("GET", "/", headers, None)
265 a8950eb7 Michael Hanselmann
        ra = _FakeRequestAuth("area1", False, None)
266 a8950eb7 Michael Hanselmann
        self.assertRaises(exc, ra.PreHandleRequest, req)
267 a8950eb7 Michael Hanselmann
268 a8950eb7 Michael Hanselmann
  def testBasicAuth(self):
269 a8950eb7 Michael Hanselmann
    for user in ["", "joe", "user name with spaces"]:
270 a8950eb7 Michael Hanselmann
      for pw in ["", "-", ":", "foobar", "Foo Bar Baz", "@@@", "###",
271 a8950eb7 Michael Hanselmann
                 "foo:bar:baz"]:
272 a8950eb7 Michael Hanselmann
        for wrong_pw in [True, False]:
273 a8950eb7 Michael Hanselmann
          basic_auth = "%s:%s" % (user, pw)
274 a8950eb7 Michael Hanselmann
          if wrong_pw:
275 a8950eb7 Michael Hanselmann
            basic_auth += "WRONG"
276 a8950eb7 Michael Hanselmann
          headers = {
277 a8950eb7 Michael Hanselmann
              http.HTTP_AUTHORIZATION:
278 a8950eb7 Michael Hanselmann
                "Basic %s" % (basic_auth.encode("base64").strip(), ),
279 a8950eb7 Michael Hanselmann
            }
280 a8950eb7 Michael Hanselmann
          req = http.server._HttpServerRequest("GET", "/", headers, None)
281 a8950eb7 Michael Hanselmann
282 a8950eb7 Michael Hanselmann
          ac = _SimpleAuthenticator(user, pw)
283 a8950eb7 Michael Hanselmann
          self.assertFalse(ac.called)
284 a8950eb7 Michael Hanselmann
          ra = _FakeRequestAuth("area1", True, ac)
285 a8950eb7 Michael Hanselmann
          if wrong_pw:
286 a8950eb7 Michael Hanselmann
            try:
287 a8950eb7 Michael Hanselmann
              ra.PreHandleRequest(req)
288 a8950eb7 Michael Hanselmann
            except http.HttpUnauthorized, err:
289 a8950eb7 Michael Hanselmann
              www_auth = err.headers[http.HTTP_WWW_AUTHENTICATE]
290 a8950eb7 Michael Hanselmann
              self.assert_(www_auth.startswith(http.auth.HTTP_BASIC_AUTH))
291 a8950eb7 Michael Hanselmann
            else:
292 a8950eb7 Michael Hanselmann
              self.fail("Didn't raise HttpUnauthorized")
293 a8950eb7 Michael Hanselmann
          else:
294 a8950eb7 Michael Hanselmann
            ra.PreHandleRequest(req)
295 a8950eb7 Michael Hanselmann
          self.assert_(ac.called)
296 a8950eb7 Michael Hanselmann
297 a8950eb7 Michael Hanselmann
298 2287b920 Michael Hanselmann
class TestReadPasswordFile(unittest.TestCase):
299 a8950eb7 Michael Hanselmann
  def testSimple(self):
300 2287b920 Michael Hanselmann
    users = http.auth.ParsePasswordFile("user1 password")
301 a8950eb7 Michael Hanselmann
    self.assertEqual(len(users), 1)
302 a8950eb7 Michael Hanselmann
    self.assertEqual(users["user1"].password, "password")
303 a8950eb7 Michael Hanselmann
    self.assertEqual(len(users["user1"].options), 0)
304 a8950eb7 Michael Hanselmann
305 a8950eb7 Michael Hanselmann
  def testOptions(self):
306 2287b920 Michael Hanselmann
    buf = StringIO()
307 2287b920 Michael Hanselmann
    buf.write("# Passwords\n")
308 2287b920 Michael Hanselmann
    buf.write("user1 password\n")
309 2287b920 Michael Hanselmann
    buf.write("\n")
310 2287b920 Michael Hanselmann
    buf.write("# Comment\n")
311 2287b920 Michael Hanselmann
    buf.write("user2 pw write,read\n")
312 2287b920 Michael Hanselmann
    buf.write("   \t# Another comment\n")
313 2287b920 Michael Hanselmann
    buf.write("invalidline\n")
314 2287b920 Michael Hanselmann
315 2287b920 Michael Hanselmann
    users = http.auth.ParsePasswordFile(buf.getvalue())
316 a8950eb7 Michael Hanselmann
    self.assertEqual(len(users), 2)
317 a8950eb7 Michael Hanselmann
    self.assertEqual(users["user1"].password, "password")
318 a8950eb7 Michael Hanselmann
    self.assertEqual(len(users["user1"].options), 0)
319 a8950eb7 Michael Hanselmann
320 a8950eb7 Michael Hanselmann
    self.assertEqual(users["user2"].password, "pw")
321 a8950eb7 Michael Hanselmann
    self.assertEqual(users["user2"].options, ["write", "read"])
322 a8950eb7 Michael Hanselmann
323 a8950eb7 Michael Hanselmann
324 33231500 Michael Hanselmann
class TestClientRequest(unittest.TestCase):
325 33231500 Michael Hanselmann
  def testRepr(self):
326 33231500 Michael Hanselmann
    cr = http.client.HttpClientRequest("localhost", 1234, "GET", "/version",
327 33231500 Michael Hanselmann
                                       headers=[], post_data="Hello World")
328 33231500 Michael Hanselmann
    self.assert_(repr(cr).startswith("<"))
329 33231500 Michael Hanselmann
330 33231500 Michael Hanselmann
  def testNoHeaders(self):
331 33231500 Michael Hanselmann
    cr = http.client.HttpClientRequest("localhost", 1234, "GET", "/version",
332 33231500 Michael Hanselmann
                                       headers=None)
333 33231500 Michael Hanselmann
    self.assert_(isinstance(cr.headers, list))
334 33231500 Michael Hanselmann
    self.assertEqual(cr.headers, [])
335 33231500 Michael Hanselmann
    self.assertEqual(cr.url, "https://localhost:1234/version")
336 33231500 Michael Hanselmann
337 abbf2cd9 Michael Hanselmann
  def testPlainAddressIPv4(self):
338 abbf2cd9 Michael Hanselmann
    cr = http.client.HttpClientRequest("192.0.2.9", 19956, "GET", "/version")
339 abbf2cd9 Michael Hanselmann
    self.assertEqual(cr.url, "https://192.0.2.9:19956/version")
340 abbf2cd9 Michael Hanselmann
341 abbf2cd9 Michael Hanselmann
  def testPlainAddressIPv6(self):
342 abbf2cd9 Michael Hanselmann
    cr = http.client.HttpClientRequest("2001:db8::cafe", 15110, "GET", "/info")
343 abbf2cd9 Michael Hanselmann
    self.assertEqual(cr.url, "https://[2001:db8::cafe]:15110/info")
344 abbf2cd9 Michael Hanselmann
345 33231500 Michael Hanselmann
  def testOldStyleHeaders(self):
346 33231500 Michael Hanselmann
    headers = {
347 33231500 Michael Hanselmann
      "Content-type": "text/plain",
348 33231500 Michael Hanselmann
      "Accept": "text/html",
349 33231500 Michael Hanselmann
      }
350 33231500 Michael Hanselmann
    cr = http.client.HttpClientRequest("localhost", 16481, "GET", "/vg_list",
351 33231500 Michael Hanselmann
                                       headers=headers)
352 33231500 Michael Hanselmann
    self.assert_(isinstance(cr.headers, list))
353 33231500 Michael Hanselmann
    self.assertEqual(sorted(cr.headers), [
354 33231500 Michael Hanselmann
      "Accept: text/html",
355 33231500 Michael Hanselmann
      "Content-type: text/plain",
356 33231500 Michael Hanselmann
      ])
357 33231500 Michael Hanselmann
    self.assertEqual(cr.url, "https://localhost:16481/vg_list")
358 33231500 Michael Hanselmann
359 33231500 Michael Hanselmann
  def testNewStyleHeaders(self):
360 33231500 Michael Hanselmann
    headers = [
361 33231500 Michael Hanselmann
      "Accept: text/html",
362 33231500 Michael Hanselmann
      "Content-type: text/plain; charset=ascii",
363 33231500 Michael Hanselmann
      "Server: httpd 1.0",
364 33231500 Michael Hanselmann
      ]
365 33231500 Michael Hanselmann
    cr = http.client.HttpClientRequest("localhost", 1234, "GET", "/version",
366 33231500 Michael Hanselmann
                                       headers=headers)
367 33231500 Michael Hanselmann
    self.assert_(isinstance(cr.headers, list))
368 33231500 Michael Hanselmann
    self.assertEqual(sorted(cr.headers), sorted(headers))
369 33231500 Michael Hanselmann
    self.assertEqual(cr.url, "https://localhost:1234/version")
370 33231500 Michael Hanselmann
371 33231500 Michael Hanselmann
  def testPostData(self):
372 33231500 Michael Hanselmann
    cr = http.client.HttpClientRequest("localhost", 1234, "GET", "/version",
373 33231500 Michael Hanselmann
                                       post_data="Hello World")
374 33231500 Michael Hanselmann
    self.assertEqual(cr.post_data, "Hello World")
375 33231500 Michael Hanselmann
376 33231500 Michael Hanselmann
  def testNoPostData(self):
377 33231500 Michael Hanselmann
    cr = http.client.HttpClientRequest("localhost", 1234, "GET", "/version")
378 33231500 Michael Hanselmann
    self.assertEqual(cr.post_data, "")
379 33231500 Michael Hanselmann
380 bac6ea51 Michael Hanselmann
  def testCompletionCallback(self):
381 bac6ea51 Michael Hanselmann
    for argname in ["completion_cb", "curl_config_fn"]:
382 bac6ea51 Michael Hanselmann
      kwargs = {
383 bac6ea51 Michael Hanselmann
        argname: NotImplementedError,
384 bac6ea51 Michael Hanselmann
        }
385 bac6ea51 Michael Hanselmann
      cr = http.client.HttpClientRequest("localhost", 14038, "GET", "/version",
386 bac6ea51 Michael Hanselmann
                                         **kwargs)
387 bac6ea51 Michael Hanselmann
      self.assertEqual(getattr(cr, argname), NotImplementedError)
388 bac6ea51 Michael Hanselmann
389 bac6ea51 Michael Hanselmann
      for fn in [NotImplemented, {}, 1]:
390 bac6ea51 Michael Hanselmann
        kwargs = {
391 bac6ea51 Michael Hanselmann
          argname: fn,
392 bac6ea51 Michael Hanselmann
          }
393 bac6ea51 Michael Hanselmann
        self.assertRaises(AssertionError, http.client.HttpClientRequest,
394 bac6ea51 Michael Hanselmann
                          "localhost", 23150, "GET", "/version", **kwargs)
395 bac6ea51 Michael Hanselmann
396 33231500 Michael Hanselmann
397 abbf2cd9 Michael Hanselmann
class _FakeCurl:
398 abbf2cd9 Michael Hanselmann
  def __init__(self):
399 abbf2cd9 Michael Hanselmann
    self.opts = {}
400 abbf2cd9 Michael Hanselmann
    self.info = NotImplemented
401 abbf2cd9 Michael Hanselmann
402 abbf2cd9 Michael Hanselmann
  def setopt(self, opt, value):
403 abbf2cd9 Michael Hanselmann
    assert opt not in self.opts, "Option set more than once"
404 abbf2cd9 Michael Hanselmann
    self.opts[opt] = value
405 abbf2cd9 Michael Hanselmann
406 abbf2cd9 Michael Hanselmann
  def getinfo(self, info):
407 abbf2cd9 Michael Hanselmann
    return self.info.pop(info)
408 abbf2cd9 Michael Hanselmann
409 abbf2cd9 Michael Hanselmann
410 abbf2cd9 Michael Hanselmann
class TestClientStartRequest(unittest.TestCase):
411 abbf2cd9 Michael Hanselmann
  @staticmethod
412 abbf2cd9 Michael Hanselmann
  def _TestCurlConfig(curl):
413 abbf2cd9 Michael Hanselmann
    curl.setopt(pycurl.SSLKEYTYPE, "PEM")
414 abbf2cd9 Michael Hanselmann
415 abbf2cd9 Michael Hanselmann
  def test(self):
416 abbf2cd9 Michael Hanselmann
    for method in [http.HTTP_GET, http.HTTP_PUT, "CUSTOM"]:
417 abbf2cd9 Michael Hanselmann
      for port in [8761, 29796, 19528]:
418 abbf2cd9 Michael Hanselmann
        for curl_config_fn in [None, self._TestCurlConfig]:
419 abbf2cd9 Michael Hanselmann
          for read_timeout in [None, 0, 1, 123, 36000]:
420 abbf2cd9 Michael Hanselmann
            self._TestInner(method, port, curl_config_fn, read_timeout)
421 abbf2cd9 Michael Hanselmann
422 abbf2cd9 Michael Hanselmann
  def _TestInner(self, method, port, curl_config_fn, read_timeout):
423 abbf2cd9 Michael Hanselmann
    for response_code in [http.HTTP_OK, http.HttpNotFound.code,
424 abbf2cd9 Michael Hanselmann
                          http.HTTP_NOT_MODIFIED]:
425 abbf2cd9 Michael Hanselmann
      for response_body in [None, "Hello World",
426 abbf2cd9 Michael Hanselmann
                            "Very Long\tContent here\n" * 171]:
427 abbf2cd9 Michael Hanselmann
        for errmsg in [None, "error"]:
428 abbf2cd9 Michael Hanselmann
          req = http.client.HttpClientRequest("localhost", port, method,
429 abbf2cd9 Michael Hanselmann
                                              "/version",
430 abbf2cd9 Michael Hanselmann
                                              curl_config_fn=curl_config_fn,
431 abbf2cd9 Michael Hanselmann
                                              read_timeout=read_timeout)
432 abbf2cd9 Michael Hanselmann
          curl = _FakeCurl()
433 abbf2cd9 Michael Hanselmann
          pending = http.client._StartRequest(curl, req)
434 abbf2cd9 Michael Hanselmann
          self.assertEqual(pending.GetCurlHandle(), curl)
435 abbf2cd9 Michael Hanselmann
          self.assertEqual(pending.GetCurrentRequest(), req)
436 abbf2cd9 Michael Hanselmann
437 abbf2cd9 Michael Hanselmann
          # Check options
438 abbf2cd9 Michael Hanselmann
          opts = curl.opts
439 abbf2cd9 Michael Hanselmann
          self.assertEqual(opts.pop(pycurl.CUSTOMREQUEST), method)
440 abbf2cd9 Michael Hanselmann
          self.assertEqual(opts.pop(pycurl.URL),
441 abbf2cd9 Michael Hanselmann
                           "https://localhost:%s/version" % port)
442 abbf2cd9 Michael Hanselmann
          if read_timeout is None:
443 abbf2cd9 Michael Hanselmann
            self.assertEqual(opts.pop(pycurl.TIMEOUT), 0)
444 abbf2cd9 Michael Hanselmann
          else:
445 abbf2cd9 Michael Hanselmann
            self.assertEqual(opts.pop(pycurl.TIMEOUT), read_timeout)
446 abbf2cd9 Michael Hanselmann
          self.assertFalse(opts.pop(pycurl.VERBOSE))
447 abbf2cd9 Michael Hanselmann
          self.assertTrue(opts.pop(pycurl.NOSIGNAL))
448 abbf2cd9 Michael Hanselmann
          self.assertEqual(opts.pop(pycurl.USERAGENT),
449 abbf2cd9 Michael Hanselmann
                           http.HTTP_GANETI_VERSION)
450 abbf2cd9 Michael Hanselmann
          self.assertEqual(opts.pop(pycurl.PROXY), "")
451 abbf2cd9 Michael Hanselmann
          self.assertFalse(opts.pop(pycurl.POSTFIELDS))
452 abbf2cd9 Michael Hanselmann
          self.assertFalse(opts.pop(pycurl.HTTPHEADER))
453 abbf2cd9 Michael Hanselmann
          write_fn = opts.pop(pycurl.WRITEFUNCTION)
454 abbf2cd9 Michael Hanselmann
          self.assertTrue(callable(write_fn))
455 abbf2cd9 Michael Hanselmann
          if hasattr(pycurl, "SSL_SESSIONID_CACHE"):
456 abbf2cd9 Michael Hanselmann
            self.assertFalse(opts.pop(pycurl.SSL_SESSIONID_CACHE))
457 abbf2cd9 Michael Hanselmann
          if curl_config_fn:
458 abbf2cd9 Michael Hanselmann
            self.assertEqual(opts.pop(pycurl.SSLKEYTYPE), "PEM")
459 abbf2cd9 Michael Hanselmann
          else:
460 abbf2cd9 Michael Hanselmann
            self.assertFalse(pycurl.SSLKEYTYPE in opts)
461 abbf2cd9 Michael Hanselmann
          self.assertFalse(opts)
462 abbf2cd9 Michael Hanselmann
463 abbf2cd9 Michael Hanselmann
          if response_body is not None:
464 abbf2cd9 Michael Hanselmann
            offset = 0
465 abbf2cd9 Michael Hanselmann
            while offset < len(response_body):
466 abbf2cd9 Michael Hanselmann
              piece = response_body[offset:offset + 10]
467 abbf2cd9 Michael Hanselmann
              write_fn(piece)
468 abbf2cd9 Michael Hanselmann
              offset += len(piece)
469 abbf2cd9 Michael Hanselmann
470 abbf2cd9 Michael Hanselmann
          curl.info = {
471 abbf2cd9 Michael Hanselmann
            pycurl.RESPONSE_CODE: response_code,
472 abbf2cd9 Michael Hanselmann
            }
473 abbf2cd9 Michael Hanselmann
474 abbf2cd9 Michael Hanselmann
          # Finalize request
475 abbf2cd9 Michael Hanselmann
          pending.Done(errmsg)
476 abbf2cd9 Michael Hanselmann
477 abbf2cd9 Michael Hanselmann
          self.assertFalse(curl.info)
478 abbf2cd9 Michael Hanselmann
479 abbf2cd9 Michael Hanselmann
          # Can only finalize once
480 abbf2cd9 Michael Hanselmann
          self.assertRaises(AssertionError, pending.Done, True)
481 abbf2cd9 Michael Hanselmann
482 abbf2cd9 Michael Hanselmann
          if errmsg:
483 abbf2cd9 Michael Hanselmann
            self.assertFalse(req.success)
484 abbf2cd9 Michael Hanselmann
          else:
485 abbf2cd9 Michael Hanselmann
            self.assertTrue(req.success)
486 abbf2cd9 Michael Hanselmann
          self.assertEqual(req.error, errmsg)
487 abbf2cd9 Michael Hanselmann
          self.assertEqual(req.resp_status_code, response_code)
488 abbf2cd9 Michael Hanselmann
          if response_body is None:
489 abbf2cd9 Michael Hanselmann
            self.assertEqual(req.resp_body, "")
490 abbf2cd9 Michael Hanselmann
          else:
491 abbf2cd9 Michael Hanselmann
            self.assertEqual(req.resp_body, response_body)
492 abbf2cd9 Michael Hanselmann
493 abbf2cd9 Michael Hanselmann
          # Check if resetting worked
494 abbf2cd9 Michael Hanselmann
          assert not hasattr(curl, "reset")
495 abbf2cd9 Michael Hanselmann
          opts = curl.opts
496 abbf2cd9 Michael Hanselmann
          self.assertFalse(opts.pop(pycurl.POSTFIELDS))
497 abbf2cd9 Michael Hanselmann
          self.assertTrue(callable(opts.pop(pycurl.WRITEFUNCTION)))
498 abbf2cd9 Michael Hanselmann
          self.assertFalse(opts)
499 abbf2cd9 Michael Hanselmann
500 abbf2cd9 Michael Hanselmann
          self.assertFalse(curl.opts,
501 abbf2cd9 Michael Hanselmann
                           msg="Previous checks did not consume all options")
502 abbf2cd9 Michael Hanselmann
          assert id(opts) == id(curl.opts)
503 33231500 Michael Hanselmann
504 abbf2cd9 Michael Hanselmann
  def _TestWrongTypes(self, *args, **kwargs):
505 abbf2cd9 Michael Hanselmann
    req = http.client.HttpClientRequest(*args, **kwargs)
506 abbf2cd9 Michael Hanselmann
    self.assertRaises(AssertionError, http.client._StartRequest,
507 abbf2cd9 Michael Hanselmann
                      _FakeCurl(), req)
508 33231500 Michael Hanselmann
509 abbf2cd9 Michael Hanselmann
  def testWrongHostType(self):
510 abbf2cd9 Michael Hanselmann
    self._TestWrongTypes(unicode("localhost"), 8080, "GET", "/version")
511 abbf2cd9 Michael Hanselmann
512 abbf2cd9 Michael Hanselmann
  def testWrongUrlType(self):
513 abbf2cd9 Michael Hanselmann
    self._TestWrongTypes("localhost", 8080, "GET", unicode("/version"))
514 abbf2cd9 Michael Hanselmann
515 abbf2cd9 Michael Hanselmann
  def testWrongMethodType(self):
516 abbf2cd9 Michael Hanselmann
    self._TestWrongTypes("localhost", 8080, unicode("GET"), "/version")
517 abbf2cd9 Michael Hanselmann
518 abbf2cd9 Michael Hanselmann
  def testWrongHeaderType(self):
519 abbf2cd9 Michael Hanselmann
    self._TestWrongTypes("localhost", 8080, "GET", "/version",
520 abbf2cd9 Michael Hanselmann
                         headers={
521 abbf2cd9 Michael Hanselmann
                           unicode("foo"): "bar",
522 abbf2cd9 Michael Hanselmann
                           })
523 abbf2cd9 Michael Hanselmann
524 abbf2cd9 Michael Hanselmann
  def testWrongPostDataType(self):
525 abbf2cd9 Michael Hanselmann
    self._TestWrongTypes("localhost", 8080, "GET", "/version",
526 abbf2cd9 Michael Hanselmann
                         post_data=unicode("verylongdata" * 100))
527 abbf2cd9 Michael Hanselmann
528 abbf2cd9 Michael Hanselmann
529 abbf2cd9 Michael Hanselmann
class _EmptyCurlMulti:
530 abbf2cd9 Michael Hanselmann
  def perform(self):
531 abbf2cd9 Michael Hanselmann
    return (pycurl.E_MULTI_OK, 0)
532 abbf2cd9 Michael Hanselmann
533 abbf2cd9 Michael Hanselmann
  def info_read(self):
534 abbf2cd9 Michael Hanselmann
    return (0, [], [])
535 abbf2cd9 Michael Hanselmann
536 abbf2cd9 Michael Hanselmann
537 abbf2cd9 Michael Hanselmann
class TestClientProcessRequests(unittest.TestCase):
538 abbf2cd9 Michael Hanselmann
  def testEmpty(self):
539 abbf2cd9 Michael Hanselmann
    requests = []
540 abbf2cd9 Michael Hanselmann
    http.client.ProcessRequests(requests, _curl=NotImplemented,
541 abbf2cd9 Michael Hanselmann
                                _curl_multi=_EmptyCurlMulti)
542 abbf2cd9 Michael Hanselmann
    self.assertEqual(requests, [])
543 abbf2cd9 Michael Hanselmann
544 abbf2cd9 Michael Hanselmann
545 abbf2cd9 Michael Hanselmann
class TestProcessCurlRequests(unittest.TestCase):
546 abbf2cd9 Michael Hanselmann
  class _FakeCurlMulti:
547 abbf2cd9 Michael Hanselmann
    def __init__(self):
548 abbf2cd9 Michael Hanselmann
      self.handles = []
549 abbf2cd9 Michael Hanselmann
      self.will_fail = []
550 abbf2cd9 Michael Hanselmann
      self._expect = ["perform"]
551 abbf2cd9 Michael Hanselmann
      self._counter = itertools.count()
552 abbf2cd9 Michael Hanselmann
553 abbf2cd9 Michael Hanselmann
    def add_handle(self, curl):
554 abbf2cd9 Michael Hanselmann
      assert curl not in self.handles
555 abbf2cd9 Michael Hanselmann
      self.handles.append(curl)
556 abbf2cd9 Michael Hanselmann
      if self._counter.next() % 3 == 0:
557 abbf2cd9 Michael Hanselmann
        self.will_fail.append(curl)
558 abbf2cd9 Michael Hanselmann
559 abbf2cd9 Michael Hanselmann
    def remove_handle(self, curl):
560 abbf2cd9 Michael Hanselmann
      self.handles.remove(curl)
561 abbf2cd9 Michael Hanselmann
562 abbf2cd9 Michael Hanselmann
    def perform(self):
563 abbf2cd9 Michael Hanselmann
      assert self._expect.pop(0) == "perform"
564 abbf2cd9 Michael Hanselmann
565 abbf2cd9 Michael Hanselmann
      if self._counter.next() % 2 == 0:
566 abbf2cd9 Michael Hanselmann
        self._expect.append("perform")
567 abbf2cd9 Michael Hanselmann
        return (pycurl.E_CALL_MULTI_PERFORM, None)
568 abbf2cd9 Michael Hanselmann
569 abbf2cd9 Michael Hanselmann
      self._expect.append("info_read")
570 abbf2cd9 Michael Hanselmann
571 abbf2cd9 Michael Hanselmann
      return (pycurl.E_MULTI_OK, len(self.handles))
572 abbf2cd9 Michael Hanselmann
573 abbf2cd9 Michael Hanselmann
    def info_read(self):
574 abbf2cd9 Michael Hanselmann
      assert self._expect.pop(0) == "info_read"
575 abbf2cd9 Michael Hanselmann
      successful = []
576 abbf2cd9 Michael Hanselmann
      failed = []
577 abbf2cd9 Michael Hanselmann
      if self.handles:
578 abbf2cd9 Michael Hanselmann
        if self._counter.next() % 17 == 0:
579 abbf2cd9 Michael Hanselmann
          curl = self.handles[0]
580 abbf2cd9 Michael Hanselmann
          if curl in self.will_fail:
581 abbf2cd9 Michael Hanselmann
            failed.append((curl, -1, "test error"))
582 abbf2cd9 Michael Hanselmann
          else:
583 abbf2cd9 Michael Hanselmann
            successful.append(curl)
584 abbf2cd9 Michael Hanselmann
        remaining_messages = len(self.handles) % 3
585 abbf2cd9 Michael Hanselmann
        if remaining_messages > 0:
586 abbf2cd9 Michael Hanselmann
          self._expect.append("info_read")
587 abbf2cd9 Michael Hanselmann
        else:
588 abbf2cd9 Michael Hanselmann
          self._expect.append("select")
589 abbf2cd9 Michael Hanselmann
      else:
590 abbf2cd9 Michael Hanselmann
        remaining_messages = 0
591 abbf2cd9 Michael Hanselmann
        self._expect.append("select")
592 abbf2cd9 Michael Hanselmann
      return (remaining_messages, successful, failed)
593 abbf2cd9 Michael Hanselmann
594 abbf2cd9 Michael Hanselmann
    def select(self, timeout):
595 abbf2cd9 Michael Hanselmann
      # Never compare floats for equality
596 abbf2cd9 Michael Hanselmann
      assert timeout >= 0.95 and timeout <= 1.05
597 abbf2cd9 Michael Hanselmann
      assert self._expect.pop(0) == "select"
598 abbf2cd9 Michael Hanselmann
      self._expect.append("perform")
599 33231500 Michael Hanselmann
600 33231500 Michael Hanselmann
  def test(self):
601 abbf2cd9 Michael Hanselmann
    requests = [_FakeCurl() for _ in range(10)]
602 abbf2cd9 Michael Hanselmann
    multi = self._FakeCurlMulti()
603 abbf2cd9 Michael Hanselmann
    for (curl, errmsg) in http.client._ProcessCurlRequests(multi, requests):
604 abbf2cd9 Michael Hanselmann
      self.assertTrue(curl not in multi.handles)
605 abbf2cd9 Michael Hanselmann
      if curl in multi.will_fail:
606 abbf2cd9 Michael Hanselmann
        self.assertTrue("test error" in errmsg)
607 abbf2cd9 Michael Hanselmann
      else:
608 abbf2cd9 Michael Hanselmann
        self.assertTrue(errmsg is None)
609 abbf2cd9 Michael Hanselmann
    self.assertFalse(multi.handles)
610 abbf2cd9 Michael Hanselmann
    self.assertEqual(multi._expect, ["select"])
611 abbf2cd9 Michael Hanselmann
612 abbf2cd9 Michael Hanselmann
613 abbf2cd9 Michael Hanselmann
class TestProcessRequests(unittest.TestCase):
614 abbf2cd9 Michael Hanselmann
  class _DummyCurlMulti:
615 abbf2cd9 Michael Hanselmann
    pass
616 abbf2cd9 Michael Hanselmann
617 abbf2cd9 Michael Hanselmann
  def testNoMonitor(self):
618 abbf2cd9 Michael Hanselmann
    self._Test(False)
619 abbf2cd9 Michael Hanselmann
620 abbf2cd9 Michael Hanselmann
  def testWithMonitor(self):
621 abbf2cd9 Michael Hanselmann
    self._Test(True)
622 abbf2cd9 Michael Hanselmann
623 abbf2cd9 Michael Hanselmann
  class _MonitorChecker:
624 abbf2cd9 Michael Hanselmann
    def __init__(self):
625 abbf2cd9 Michael Hanselmann
      self._monitor = None
626 abbf2cd9 Michael Hanselmann
627 abbf2cd9 Michael Hanselmann
    def GetMonitor(self):
628 abbf2cd9 Michael Hanselmann
      return self._monitor
629 abbf2cd9 Michael Hanselmann
630 abbf2cd9 Michael Hanselmann
    def __call__(self, monitor):
631 abbf2cd9 Michael Hanselmann
      assert callable(monitor.GetLockInfo)
632 abbf2cd9 Michael Hanselmann
      self._monitor = monitor
633 abbf2cd9 Michael Hanselmann
634 abbf2cd9 Michael Hanselmann
  def _Test(self, use_monitor):
635 abbf2cd9 Michael Hanselmann
    def cfg_fn(port, curl):
636 abbf2cd9 Michael Hanselmann
      curl.opts["__port__"] = port
637 abbf2cd9 Michael Hanselmann
638 bac6ea51 Michael Hanselmann
    def _LockCheckReset(monitor, req):
639 abbf2cd9 Michael Hanselmann
      self.assertTrue(monitor._lock.is_owned(shared=0),
640 abbf2cd9 Michael Hanselmann
                      msg="Lock must be owned in exclusive mode")
641 bac6ea51 Michael Hanselmann
      assert not hasattr(req, "lockcheck__")
642 bac6ea51 Michael Hanselmann
      setattr(req, "lockcheck__", True)
643 bac6ea51 Michael Hanselmann
644 bac6ea51 Michael Hanselmann
    def _BuildNiceName(port, default=None):
645 bac6ea51 Michael Hanselmann
      if port % 5 == 0:
646 bac6ea51 Michael Hanselmann
        return "nicename%s" % port
647 bac6ea51 Michael Hanselmann
      else:
648 bac6ea51 Michael Hanselmann
        # Use standard name
649 bac6ea51 Michael Hanselmann
        return default
650 abbf2cd9 Michael Hanselmann
651 abbf2cd9 Michael Hanselmann
    requests = \
652 abbf2cd9 Michael Hanselmann
      [http.client.HttpClientRequest("localhost", i, "POST", "/version%s" % i,
653 bac6ea51 Michael Hanselmann
                                     curl_config_fn=compat.partial(cfg_fn, i),
654 bac6ea51 Michael Hanselmann
                                     completion_cb=NotImplementedError,
655 bac6ea51 Michael Hanselmann
                                     nicename=_BuildNiceName(i))
656 abbf2cd9 Michael Hanselmann
       for i in range(15176, 15501)]
657 abbf2cd9 Michael Hanselmann
    requests_count = len(requests)
658 abbf2cd9 Michael Hanselmann
659 abbf2cd9 Michael Hanselmann
    if use_monitor:
660 abbf2cd9 Michael Hanselmann
      lock_monitor_cb = self._MonitorChecker()
661 abbf2cd9 Michael Hanselmann
    else:
662 abbf2cd9 Michael Hanselmann
      lock_monitor_cb = None
663 abbf2cd9 Michael Hanselmann
664 abbf2cd9 Michael Hanselmann
    def _ProcessRequests(multi, handles):
665 abbf2cd9 Michael Hanselmann
      self.assertTrue(isinstance(multi, self._DummyCurlMulti))
666 abbf2cd9 Michael Hanselmann
      self.assertEqual(len(requests), len(handles))
667 abbf2cd9 Michael Hanselmann
      self.assertTrue(compat.all(isinstance(curl, _FakeCurl)
668 abbf2cd9 Michael Hanselmann
                                 for curl in handles))
669 abbf2cd9 Michael Hanselmann
670 bac6ea51 Michael Hanselmann
      # Prepare for lock check
671 bac6ea51 Michael Hanselmann
      for req in requests:
672 bac6ea51 Michael Hanselmann
        assert req.completion_cb is NotImplementedError
673 bac6ea51 Michael Hanselmann
        if use_monitor:
674 bac6ea51 Michael Hanselmann
          req.completion_cb = \
675 bac6ea51 Michael Hanselmann
            compat.partial(_LockCheckReset, lock_monitor_cb.GetMonitor())
676 bac6ea51 Michael Hanselmann
677 abbf2cd9 Michael Hanselmann
      for idx, curl in enumerate(handles):
678 bac6ea51 Michael Hanselmann
        try:
679 bac6ea51 Michael Hanselmann
          port = curl.opts["__port__"]
680 bac6ea51 Michael Hanselmann
        except KeyError:
681 bac6ea51 Michael Hanselmann
          self.fail("Per-request config function was not called")
682 abbf2cd9 Michael Hanselmann
683 abbf2cd9 Michael Hanselmann
        if use_monitor:
684 abbf2cd9 Michael Hanselmann
          # Check if lock information is correct
685 abbf2cd9 Michael Hanselmann
          lock_info = lock_monitor_cb.GetMonitor().GetLockInfo(None)
686 abbf2cd9 Michael Hanselmann
          expected = \
687 bac6ea51 Michael Hanselmann
            [("rpc/%s" % (_BuildNiceName(handle.opts["__port__"],
688 bac6ea51 Michael Hanselmann
                                         default=("localhost/version%s" %
689 bac6ea51 Michael Hanselmann
                                                  handle.opts["__port__"]))),
690 bac6ea51 Michael Hanselmann
              None,
691 abbf2cd9 Michael Hanselmann
              [threading.currentThread().getName()], None)
692 abbf2cd9 Michael Hanselmann
             for handle in handles[idx:]]
693 abbf2cd9 Michael Hanselmann
          self.assertEqual(sorted(lock_info), sorted(expected))
694 abbf2cd9 Michael Hanselmann
695 abbf2cd9 Michael Hanselmann
        if port % 3 == 0:
696 abbf2cd9 Michael Hanselmann
          response_code = http.HTTP_OK
697 abbf2cd9 Michael Hanselmann
          msg = None
698 abbf2cd9 Michael Hanselmann
        else:
699 abbf2cd9 Michael Hanselmann
          response_code = http.HttpNotFound.code
700 abbf2cd9 Michael Hanselmann
          msg = "test error"
701 abbf2cd9 Michael Hanselmann
702 abbf2cd9 Michael Hanselmann
        curl.info = {
703 abbf2cd9 Michael Hanselmann
          pycurl.RESPONSE_CODE: response_code,
704 abbf2cd9 Michael Hanselmann
          }
705 abbf2cd9 Michael Hanselmann
706 bac6ea51 Michael Hanselmann
        # Prepare for reset
707 bac6ea51 Michael Hanselmann
        self.assertFalse(curl.opts.pop(pycurl.POSTFIELDS))
708 bac6ea51 Michael Hanselmann
        self.assertTrue(callable(curl.opts.pop(pycurl.WRITEFUNCTION)))
709 abbf2cd9 Michael Hanselmann
710 abbf2cd9 Michael Hanselmann
        yield (curl, msg)
711 abbf2cd9 Michael Hanselmann
712 abbf2cd9 Michael Hanselmann
      if use_monitor:
713 bac6ea51 Michael Hanselmann
        self.assertTrue(compat.all(req.lockcheck__ for req in requests))
714 bac6ea51 Michael Hanselmann
715 bac6ea51 Michael Hanselmann
    if use_monitor:
716 bac6ea51 Michael Hanselmann
      self.assertEqual(lock_monitor_cb.GetMonitor(), None)
717 abbf2cd9 Michael Hanselmann
718 abbf2cd9 Michael Hanselmann
    http.client.ProcessRequests(requests, lock_monitor_cb=lock_monitor_cb,
719 abbf2cd9 Michael Hanselmann
                                _curl=_FakeCurl,
720 abbf2cd9 Michael Hanselmann
                                _curl_multi=self._DummyCurlMulti,
721 abbf2cd9 Michael Hanselmann
                                _curl_process=_ProcessRequests)
722 abbf2cd9 Michael Hanselmann
    for req in requests:
723 abbf2cd9 Michael Hanselmann
      if req.port % 3 == 0:
724 abbf2cd9 Michael Hanselmann
        self.assertTrue(req.success)
725 abbf2cd9 Michael Hanselmann
        self.assertEqual(req.error, None)
726 abbf2cd9 Michael Hanselmann
      else:
727 abbf2cd9 Michael Hanselmann
        self.assertFalse(req.success)
728 abbf2cd9 Michael Hanselmann
        self.assertTrue("test error" in req.error)
729 abbf2cd9 Michael Hanselmann
730 abbf2cd9 Michael Hanselmann
    # See if monitor was disabled
731 abbf2cd9 Michael Hanselmann
    if use_monitor:
732 abbf2cd9 Michael Hanselmann
      monitor = lock_monitor_cb.GetMonitor()
733 abbf2cd9 Michael Hanselmann
      self.assertEqual(monitor._pending_fn, None)
734 abbf2cd9 Michael Hanselmann
      self.assertEqual(monitor.GetLockInfo(None), [])
735 abbf2cd9 Michael Hanselmann
    else:
736 abbf2cd9 Michael Hanselmann
      self.assertEqual(lock_monitor_cb, None)
737 abbf2cd9 Michael Hanselmann
738 abbf2cd9 Michael Hanselmann
    self.assertEqual(len(requests), requests_count)
739 abbf2cd9 Michael Hanselmann
740 abbf2cd9 Michael Hanselmann
  def testBadRequest(self):
741 abbf2cd9 Michael Hanselmann
    bad_request = http.client.HttpClientRequest("localhost", 27784,
742 abbf2cd9 Michael Hanselmann
                                                "POST", "/version")
743 abbf2cd9 Michael Hanselmann
    bad_request.success = False
744 abbf2cd9 Michael Hanselmann
745 abbf2cd9 Michael Hanselmann
    self.assertRaises(AssertionError, http.client.ProcessRequests,
746 abbf2cd9 Michael Hanselmann
                      [bad_request], _curl=NotImplemented,
747 abbf2cd9 Michael Hanselmann
                      _curl_multi=NotImplemented, _curl_process=NotImplemented)
748 33231500 Michael Hanselmann
749 33231500 Michael Hanselmann
750 2f96c43c Michael Hanselmann
if __name__ == "__main__":
751 25231ec5 Michael Hanselmann
  testutils.GanetiTestProgram()