~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_http.py

  • Committer: Vincent Ladeuil
  • Date: 2009-01-30 00:49:41 UTC
  • mto: (3982.1.1 bzr.integration)
  • mto: This revision was merged to the branch mainline in revision 3983.
  • Revision ID: v.ladeuil+lp@free.fr-20090130004941-820fpd2ryyo127vv
Add more tests, fix pycurl double handling, revert previous tracking.

* bzrlib/tests/test_http.py:
(PredefinedRequestHandler): Renamed from
PreRecordedRequestHandler.
(PredefinedRequestHandler.handle_one_request): Get the canned
response from the test server directly.
(ActivityServerMixin): Make it a true object and intialize the
attributes in the constructor. Tests can now set the
canned_response attribute before querying the server.
(TestActivity.setUp, TestActivity.tearDown,
TestActivity.get_transport, TestActivity.assertActivitiesMatch):
Extracted from test_get to be able to write other tests.
(TestActivity.test_has, TestActivity.test_readv,
TestActivity.test_post): New tests, all cases should be covered
now.

* bzrlib/transport/http/response.py:
(RangeFile.__init__, RangeFile.read, handle_response): Revert
previous tracking, both http implementations can now report
activity from the socket.

* bzrlib/transport/http/_pycurl.py:
(PyCurlTransport._get_ranged, PyCurlTransport._post): Revert
previous tracking.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1794
1794
        self.assertEquals(t._user, r._user)
1795
1795
 
1796
1796
 
1797
 
class ActivityServerMixin(object):
1798
 
 
1799
 
    # Bytes read and written by the server
1800
 
    bytes_read = 0
1801
 
    bytes_written = 0
1802
 
 
1803
 
 
1804
 
class ActivityHTTPServer(ActivityServerMixin, http_server.HttpServer):
1805
 
    pass
1806
 
 
1807
 
 
1808
 
if tests.HTTPSServerFeature.available():
1809
 
    from bzrlib.tests import https_server
1810
 
    class ActivityHTTPSServer(ActivityServerMixin, https_server.HTTPSServer):
1811
 
        pass
1812
 
 
1813
 
 
1814
 
class PreRecordedRequestHandler(http_server.TestingHTTPRequestHandler):
1815
 
    """Pre-recorded request handler.
1816
 
 
 
1797
class PredefinedRequestHandler(http_server.TestingHTTPRequestHandler):
 
1798
    """Request handler for a unique and pre-defined request.
1817
1799
 
1818
1800
    The only thing we care about here is how many bytes travel on the wire. But
1819
1801
    since we want to measure it for a real http client, we have to send it
1824
1806
    line.
1825
1807
    """
1826
1808
 
1827
 
    canned_response = ''
1828
 
 
1829
1809
    def handle_one_request(self):
1830
1810
        tcs = self.server.test_case_server
1831
 
        if not isinstance(tcs, ActivityServerMixin):
1832
 
            raise AssertionError(
1833
 
                'PreRecoredRequestHandler assumes a %r server, not %r'
1834
 
                % (ActivityHttpServer, tcs))
1835
1811
        requestline = self.rfile.readline()
1836
1812
        headers = self.MessageClass(self.rfile, 0)
1837
1813
        # We just read: the request, the headers, an empty line indicating the
1840
1816
        for line in headers.headers:
1841
1817
            bytes_read += len(line)
1842
1818
        bytes_read += len('\r\n')
 
1819
        if requestline.startswith('POST'):
 
1820
            # The body should be a single line (or we don't know where it ends
 
1821
            # and we don't want to issue a blocking read)
 
1822
            body = self.rfile.readline()
 
1823
            bytes_read += len(body)
1843
1824
        tcs.bytes_read = bytes_read
1844
 
        # Set the bytes written *before* issuing the write, the client is
1845
 
        # supposed to consume every produced byte *before* checkingthat value.
 
1825
 
 
1826
        # We set the bytes written *before* issuing the write, the client is
 
1827
        # supposed to consume every produced byte *before* checking that value.
1846
1828
 
1847
1829
        # Doing the oppposite may lead to test failure: we may be interrupted
1848
1830
        # after the write but before updating the value. The client can then
1849
1831
        # continue and read the value *before* we can update it. And yes,
1850
1832
        # this has been observed -- vila 20090129
1851
 
        tcs.bytes_written = len(self.canned_response)
1852
 
        self.wfile.write(self.canned_response)
 
1833
        tcs.bytes_written = len(tcs.canned_response)
 
1834
        self.wfile.write(tcs.canned_response)
 
1835
 
 
1836
 
 
1837
class ActivityServerMixin(object):
 
1838
 
 
1839
    def __init__(self, protocol_version):
 
1840
        super(ActivityServerMixin, self).__init__(
 
1841
            request_handler=PredefinedRequestHandler,
 
1842
            protocol_version=protocol_version)
 
1843
        # Bytes read and written by the server
 
1844
        self.bytes_read = 0
 
1845
        self.bytes_written = 0
 
1846
        self.canned_response = None
 
1847
 
 
1848
 
 
1849
class ActivityHTTPServer(ActivityServerMixin, http_server.HttpServer):
 
1850
    pass
 
1851
 
 
1852
 
 
1853
if tests.HTTPSServerFeature.available():
 
1854
    from bzrlib.tests import https_server
 
1855
    class ActivityHTTPSServer(ActivityServerMixin, https_server.HTTPSServer):
 
1856
        pass
1853
1857
 
1854
1858
 
1855
1859
class TestActivity(tests.TestCase):
1859
1863
    be able to predict the activity on the client socket.
1860
1864
    """
1861
1865
 
1862
 
    def test_http_get(self):
1863
 
        class MyRequestHandler(PreRecordedRequestHandler):
1864
 
 
1865
 
            canned_response = '''HTTP/1.1 200 OK\r
1866
 
Date: Tue, 11 Jul 2006 04:32:56 GMT\r
1867
 
Server: Apache/2.0.54 (Fedora)\r
1868
 
Last-Modified: Sun, 23 Apr 2006 19:35:20 GMT\r
1869
 
ETag: "56691-23-38e9ae00"\r
1870
 
Accept-Ranges: bytes\r
1871
 
Content-Length: 35\r
1872
 
Connection: close\r
1873
 
Content-Type: text/plain; charset=UTF-8\r
1874
 
\r
1875
 
Bazaar-NG meta directory, format 1
1876
 
'''
1877
 
 
1878
 
        server =  self._activity_server(MyRequestHandler,
1879
 
                                        self._protocol_version)
1880
 
        server.setUp()
1881
 
        self.addCleanup(server.tearDown)
1882
 
 
1883
 
        activities = {}
 
1866
    def setUp(self):
 
1867
        tests.TestCase.setUp(self)
 
1868
        self.server = self._activity_server(self._protocol_version)
 
1869
        self.server.setUp()
 
1870
        self.activities = {}
1884
1871
        def report_activity(t, bytes, direction):
1885
 
            count = activities.get(direction, 0)
 
1872
            count = self.activities.get(direction, 0)
1886
1873
            count += bytes
1887
 
            activities[direction] = count
 
1874
            self.activities[direction] = count
1888
1875
 
1889
1876
        # We override at class level because constructors may propagate the
1890
1877
        # bound method and render instance overriding ineffective (an
1891
1878
        # alternative would be be to define a specific ui factory instead...)
1892
 
        orig_ra = self._transport._report_activity
1893
 
        def restore_report_activity():
1894
 
            self._transport._report_activity = orig_ra
1895
 
        self.addCleanup(restore_report_activity)
 
1879
        self.orig_report_activity = self._transport._report_activity
1896
1880
        self._transport._report_activity = report_activity
1897
1881
 
1898
 
        t = self._transport(server.get_url())
1899
 
 
 
1882
    def tearDown(self):
 
1883
        self._transport._report_activity = self.orig_report_activity
 
1884
        self.server.tearDown()
 
1885
        tests.TestCase.tearDown(self)
 
1886
 
 
1887
    def get_transport(self):
 
1888
        return self._transport(self.server.get_url())
 
1889
 
 
1890
    def assertActivitiesMatch(self):
 
1891
        self.assertEqual(self.server.bytes_read,
 
1892
                         self.activities.get('write', 0), 'written bytes')
 
1893
        self.assertEqual(self.server.bytes_written,
 
1894
                         self.activities.get('read', 0), 'read bytes')
 
1895
 
 
1896
    def test_get(self):
 
1897
        self.server.canned_response = '''HTTP/1.1 200 OK\r
 
1898
Date: Tue, 11 Jul 2006 04:32:56 GMT\r
 
1899
Server: Apache/2.0.54 (Fedora)\r
 
1900
Last-Modified: Sun, 23 Apr 2006 19:35:20 GMT\r
 
1901
ETag: "56691-23-38e9ae00"\r
 
1902
Accept-Ranges: bytes\r
 
1903
Content-Length: 35\r
 
1904
Connection: close\r
 
1905
Content-Type: text/plain; charset=UTF-8\r
 
1906
\r
 
1907
Bazaar-NG meta directory, format 1
 
1908
'''
 
1909
        t = self.get_transport()
1900
1910
        self.assertEqual('Bazaar-NG meta directory, format 1\n',
1901
1911
                         t.get('foo/bar').read())
1902
 
        self.assertEqual(server.bytes_read, activities.get('write', 0))
1903
 
        self.assertEqual(server.bytes_written, activities.get('read', 0))
 
1912
        self.assertActivitiesMatch()
 
1913
 
 
1914
    def test_has(self):
 
1915
        self.server.canned_response = '''HTTP/1.1 200 OK\r
 
1916
Server: SimpleHTTP/0.6 Python/2.5.2\r
 
1917
Date: Thu, 29 Jan 2009 20:21:47 GMT\r
 
1918
Content-type: application/octet-stream\r
 
1919
Content-Length: 20\r
 
1920
Last-Modified: Thu, 29 Jan 2009 20:21:47 GMT\r
 
1921
\r
 
1922
'''
 
1923
        t = self.get_transport()
 
1924
        self.assertTrue(t.has('foo/bar'))
 
1925
        self.assertActivitiesMatch()
 
1926
 
 
1927
    def test_readv(self):
 
1928
        self.server.canned_response = '''HTTP/1.1 206 Partial Content\r
 
1929
Date: Tue, 11 Jul 2006 04:49:48 GMT\r
 
1930
Server: Apache/2.0.54 (Fedora)\r
 
1931
Last-Modified: Thu, 06 Jul 2006 20:22:05 GMT\r
 
1932
ETag: "238a3c-16ec2-805c5540"\r
 
1933
Accept-Ranges: bytes\r
 
1934
Content-Length: 1534\r
 
1935
Connection: close\r
 
1936
Content-Type: multipart/byteranges; boundary=418470f848b63279b\r
 
1937
\r
 
1938
\r
 
1939
--418470f848b63279b\r
 
1940
Content-type: text/plain; charset=UTF-8\r
 
1941
Content-range: bytes 0-254/93890\r
 
1942
\r
 
1943
mbp@sourcefrog.net-20050309040815-13242001617e4a06
 
1944
mbp@sourcefrog.net-20050309040929-eee0eb3e6d1e7627
 
1945
mbp@sourcefrog.net-20050309040957-6cad07f466bb0bb8
 
1946
mbp@sourcefrog.net-20050309041501-c840e09071de3b67
 
1947
mbp@sourcefrog.net-20050309044615-c24a3250be83220a
 
1948
\r
 
1949
--418470f848b63279b\r
 
1950
Content-type: text/plain; charset=UTF-8\r
 
1951
Content-range: bytes 1000-2049/93890\r
 
1952
\r
 
1953
40-fd4ec249b6b139ab
 
1954
mbp@sourcefrog.net-20050311063625-07858525021f270b
 
1955
mbp@sourcefrog.net-20050311231934-aa3776aff5200bb9
 
1956
mbp@sourcefrog.net-20050311231953-73aeb3a131c3699a
 
1957
mbp@sourcefrog.net-20050311232353-f5e33da490872c6a
 
1958
mbp@sourcefrog.net-20050312071639-0a8f59a34a024ff0
 
1959
mbp@sourcefrog.net-20050312073432-b2c16a55e0d6e9fb
 
1960
mbp@sourcefrog.net-20050312073831-a47c3335ece1920f
 
1961
mbp@sourcefrog.net-20050312085412-13373aa129ccbad3
 
1962
mbp@sourcefrog.net-20050313052251-2bf004cb96b39933
 
1963
mbp@sourcefrog.net-20050313052856-3edd84094687cb11
 
1964
mbp@sourcefrog.net-20050313053233-e30a4f28aef48f9d
 
1965
mbp@sourcefrog.net-20050313053853-7c64085594ff3072
 
1966
mbp@sourcefrog.net-20050313054757-a86c3f5871069e22
 
1967
mbp@sourcefrog.net-20050313061422-418f1f73b94879b9
 
1968
mbp@sourcefrog.net-20050313120651-497bd231b19df600
 
1969
mbp@sourcefrog.net-20050314024931-eae0170ef25a5d1a
 
1970
mbp@sourcefrog.net-20050314025438-d52099f915fe65fc
 
1971
mbp@sourcefrog.net-20050314025539-637a636692c055cf
 
1972
mbp@sourcefrog.net-20050314025737-55eb441f430ab4ba
 
1973
mbp@sourcefrog.net-20050314025901-d74aa93bb7ee8f62
 
1974
mbp@source\r
 
1975
--418470f848b63279b--\r
 
1976
'''
 
1977
        t = self.get_transport()
 
1978
        # Remember that the request is ignored and that the ranges below
 
1979
        # doesn't have to match the canned response.
 
1980
        l = list(t.readv('/foo/bar', ((0, 255), (1000, 1050))))
 
1981
        self.assertEqual(2, len(l))
 
1982
        self.assertActivitiesMatch()
 
1983
 
 
1984
    def test_post(self):
 
1985
        self.server.canned_response = '''HTTP/1.1 200 OK\r
 
1986
Date: Tue, 11 Jul 2006 04:32:56 GMT\r
 
1987
Server: Apache/2.0.54 (Fedora)\r
 
1988
Last-Modified: Sun, 23 Apr 2006 19:35:20 GMT\r
 
1989
ETag: "56691-23-38e9ae00"\r
 
1990
Accept-Ranges: bytes\r
 
1991
Content-Length: 35\r
 
1992
Connection: close\r
 
1993
Content-Type: text/plain; charset=UTF-8\r
 
1994
\r
 
1995
lalala whatever as long as itsssss
 
1996
'''
 
1997
        t = self.get_transport()
 
1998
        # We must send a single line of body bytes, see
 
1999
        # PredefinedRequestHandler.handle_one_request
 
2000
        code, f = t._post('abc def end-of-body\n')
 
2001
        self.assertEqual('lalala whatever as long as itsssss\n', f.read())
 
2002
        self.assertActivitiesMatch()