Still need to add tests for the Peer and Cache Managers.
"""Serve local requests from apt and remote requests from peers."""
-from urllib import unquote_plus
+from urllib import quote_plus, unquote_plus
from binascii import b2a_hex
from twisted.python import log
from twisted.internet import defer
from twisted.web2 import server, http, resource, channel, stream
from twisted.web2 import static, http_headers, responsecode
+from twisted.trial import unittest
+from twisted.python.filepath import FilePath
from policies import ThrottlingFactory, ThrottlingProtocol, ProtocolWrapper
from apt_p2p_Khashmir.bencode import bencode
def render(self, ctx):
"""Render a web page with descriptive statistics."""
- return http.Response(
- 200,
- {'content-type': http_headers.MimeType('text', 'html')},
- self.manager.getStats())
+ if self.manager:
+ return http.Response(
+ 200,
+ {'content-type': http_headers.MimeType('text', 'html')},
+ self.manager.getStats())
+ else:
+ return http.Response(
+ 200,
+ {'content-type': http_headers.MimeType('text', 'html')},
+ '<html><body><p>Some Statistics</body></html>')
def locateChild(self, request, segments):
"""Process the incoming request."""
log.msg('Got a malformed request for "%s" from %s' % (request.uri, request.remoteAddr))
return None, ()
+class TestTopLevel(unittest.TestCase):
+ """Unit tests for the HTTP Server."""
+
+ client = None
+ pending_calls = []
+ torrent_hash = '\xca \xb8\x0c\x00\xe7\x07\xf8~])+\x9d\xe5_B\xff\x1a\xc4!'
+ torrent = 'abcdefghij0123456789\xca\xec\xb8\x0c\x00\xe7\x07\xf8~])\x8f\x9d\xe5_B\xff\x1a\xc4!'
+ file_hash = '\xf8~])+\x9d\xe5_B\xff\x1a\xc4!\xca \xb8\x0c\x00\xe7\x07'
+
+ def setUp(self):
+ self.client = TopLevel(FilePath('/boot'), self, None, 0)
+
+ def lookupHash(self, hash):
+ if hash == self.torrent_hash:
+ return [{'pieces': self.torrent}]
+ elif hash == self.file_hash:
+ return [{'path': FilePath('/boot/initrd')}]
+ else:
+ return []
+
+ def create_request(self, host, path):
+ req = server.Request(None, 'GET', path, (1,1), 0, http_headers.Headers())
+ class addr:
+ host = ''
+ port = 0
+ req.remoteAddr = addr()
+ req.remoteAddr.host = host
+ req.remoteAddr.port = 23456
+ server.Request._parseURL(req)
+ return req
+
+ def test_unauthorized(self):
+ req = self.create_request('128.0.0.1', '/foo/bar')
+ self.failUnlessRaises(http.HTTPError, req._getChild, None, self.client, req.postpath)
+
+ def test_Packages_diff(self):
+ req = self.create_request('127.0.0.1',
+ '/ftp.us.debian.org/debian/dists/unstable/main/binary-i386/Packages.diff/Index')
+ self.failUnlessRaises(http.HTTPError, req._getChild, None, self.client, req.postpath)
+
+ def test_Statistics(self):
+ req = self.create_request('127.0.0.1', '/')
+ res = req._getChild(None, self.client, req.postpath)
+ self.failIfEqual(res, None)
+ df = defer.maybeDeferred(res.renderHTTP, req)
+ df.addCallback(self.check_resp, 200)
+ return df
+
+ def test_apt_download(self):
+ req = self.create_request('127.0.0.1',
+ '/ftp.us.debian.org/debian/dists/stable/Release')
+ res = req._getChild(None, self.client, req.postpath)
+ self.failIfEqual(res, None)
+ self.failUnless(isinstance(res, FileDownloader))
+ df = defer.maybeDeferred(res.renderHTTP, req)
+ df.addCallback(self.check_resp, 404)
+ return df
+
+ def test_torrent_upload(self):
+ req = self.create_request('123.45.67.89',
+ '/~/' + quote_plus(self.torrent_hash))
+ res = req._getChild(None, self.client, req.postpath)
+ self.failIfEqual(res, None)
+ self.failUnless(isinstance(res, static.Data))
+ df = defer.maybeDeferred(res.renderHTTP, req)
+ df.addCallback(self.check_resp, 200)
+ return df
+
+ def test_file_upload(self):
+ req = self.create_request('123.45.67.89',
+ '/~/' + quote_plus(self.file_hash))
+ res = req._getChild(None, self.client, req.postpath)
+ self.failIfEqual(res, None)
+ self.failUnless(isinstance(res, FileUploader))
+ df = defer.maybeDeferred(res.renderHTTP, req)
+ df.addCallback(self.check_resp, 200)
+ return df
+
+ def test_missing_hash(self):
+ req = self.create_request('123.45.67.89',
+ '/~/' + quote_plus('foobar'))
+ self.failUnlessRaises(http.HTTPError, req._getChild, None, self.client, req.postpath)
+
+ def check_resp(self, resp, code):
+ self.failUnlessEqual(resp.code, code)
+ return resp
+
+ def tearDown(self):
+ for p in self.pending_calls:
+ if p.active():
+ p.cancel()
+ self.pending_calls = []
+ if self.client:
+ self.client = None
+
if __name__ == '__builtin__':
# Running from twistd -ny HTTPServer.py
# Then test with:
manager = None
pending_calls = []
- def gotResp(self, resp, num, expect):
- self.failUnless(resp.code >= 200 and resp.code < 300, "Got a non-200 response: %r" % resp.code)
- if expect is not None:
- self.failUnless(resp.stream.length == expect, "Length was incorrect, got %r, expected %r" % (resp.stream.length, expect))
- def print_(n):
- pass
- def printdone(n):
- pass
- stream.readStream(resp.stream, print_).addCallback(printdone)
-
- def test_download(self):
- """Tests a normal download."""
- self.manager = PeerManager()
- self.timeout = 10
-
- host = 'www.ietf.org'
- d = self.manager.get('', 'http://' + host + '/rfc/rfc0013.txt')
- d.addCallback(self.gotResp, 1, 1070)
- return d
-
- def test_head(self):
- """Tests a 'HEAD' request."""
- self.manager = PeerManager()
- self.timeout = 10
-
- host = 'www.ietf.org'
- d = self.manager.get('', 'http://' + host + '/rfc/rfc0013.txt', method = "HEAD")
- d.addCallback(self.gotResp, 1, 0)
- return d
-
- def test_multiple_downloads(self):
- """Tests multiple downloads with queueing and connection closing."""
- self.manager = PeerManager()
- self.timeout = 120
- lastDefer = defer.Deferred()
-
- def newRequest(host, path, num, expect, last=False):
- d = self.manager.get('', 'http://' + host + ':' + str(80) + path)
- d.addCallback(self.gotResp, num, expect)
- if last:
- d.addBoth(lastDefer.callback)
-
- newRequest('www.ietf.org', "/rfc/rfc0006.txt", 1, 1776)
- newRequest('www.ietf.org', "/rfc/rfc2362.txt", 2, 159833)
- newRequest('www.google.ca', "/", 3, None)
- self.pending_calls.append(reactor.callLater(1, newRequest, 'www.sfu.ca', '/', 4, None))
- self.pending_calls.append(reactor.callLater(10, newRequest, 'www.ietf.org', '/rfc/rfc0048.txt', 5, 41696))
- self.pending_calls.append(reactor.callLater(30, newRequest, 'www.ietf.org', '/rfc/rfc0022.txt', 6, 4606))
- self.pending_calls.append(reactor.callLater(31, newRequest, 'www.sfu.ca', '/studentcentral/index.html', 7, None))
- self.pending_calls.append(reactor.callLater(32, newRequest, 'www.ietf.org', '/rfc/rfc0014.txt', 8, 27))
- self.pending_calls.append(reactor.callLater(32, newRequest, 'www.ietf.org', '/rfc/rfc0001.txt', 9, 21088))
- self.pending_calls.append(reactor.callLater(62, newRequest, 'www.google.ca', '/intl/en/options/', 0, None, True))
- return lastDefer
-
def tearDown(self):
for p in self.pending_calls:
if p.active():
from ConfigParser import SafeConfigParser
from twisted.python import log, versions
+from twisted.trial import unittest
class ConfigError(Exception):
"""Errors that occur in the loading of configuration variables."""
config.add_section(config.get('DEFAULT', 'DHT'))
for k in DHT_DEFAULTS:
config.set(config.get('DEFAULT', 'DHT'), k, DHT_DEFAULTS[k])
+
+class TestConfigParser(unittest.TestCase):
+ """Unit tests for the config parser."""
+
+ def test_uppercase(self):
+ config.set('DEFAULT', 'case_tester', 'foo')
+ self.failUnless(config.get('DEFAULT', 'CASE_TESTER') == 'foo')
+ self.failUnless(config.get('DEFAULT', 'case_tester') == 'foo')
+ config.set('DEFAULT', 'TEST_CASE', 'bar')
+ self.failUnless(config.get('DEFAULT', 'TEST_CASE') == 'bar')
+ self.failUnless(config.get('DEFAULT', 'test_case') == 'bar')
+ config.set('DEFAULT', 'FINAL_test_CASE', 'foobar')
+ self.failUnless(config.get('DEFAULT', 'FINAL_TEST_CASE') == 'foobar')
+ self.failUnless(config.get('DEFAULT', 'final_test_case') == 'foobar')
+ self.failUnless(config.get('DEFAULT', 'FINAL_test_CASE') == 'foobar')
+ self.failUnless(config.get('DEFAULT', 'final_TEST_case') == 'foobar')
+
+ def test_time(self):
+ config.set('DEFAULT', 'time_tester_1', '2d')
+ self.failUnless(config.gettime('DEFAULT', 'time_tester_1') == 2*86400)
+ config.set('DEFAULT', 'time_tester_2', '3h')
+ self.failUnless(config.gettime('DEFAULT', 'time_tester_2') == 3*3600)
+ config.set('DEFAULT', 'time_tester_3', '4m')
+ self.failUnless(config.gettime('DEFAULT', 'time_tester_3') == 4*60)
+ config.set('DEFAULT', 'time_tester_4', '37s')
+ self.failUnless(config.gettime('DEFAULT', 'time_tester_4') == 37)
+
+ def test_string(self):
+ config.set('DEFAULT', 'string_test', 'foobar')
+ self.failUnless(type(config.getstring('DEFAULT', 'string_test')) == str)
+ self.failUnless(config.getstring('DEFAULT', 'string_test') == 'foobar')
+
+ def test_stringlist(self):
+ config.set('DEFAULT', 'stringlist_test', """foo
+ bar
+ foobar """)
+ l = config.getstringlist('DEFAULT', 'stringlist_test')
+ self.failUnless(type(l) == list)
+ self.failUnless(len(l) == 3)
+ self.failUnless(l[0] == 'foo')
+ self.failUnless(l[1] == 'bar')
+ self.failUnless(l[2] == 'foobar')
+
\ No newline at end of file
def test_Value(self):
self.store.storeValue(self.key, self.key)
+ self.failUnlessEqual(self.store.countValues(self.key), 1)
val = self.store.retrieveValues(self.key)
self.failUnlessEqual(len(val), 1)
self.failUnlessEqual(val[0], self.key)
def testUnknownMeth(self):
df = self.a.connectionForAddr(('127.0.0.1', 1181)).sendRequest('blahblah', {'msg' : "This is a test."})
+ df = self.failUnlessFailure(df, KrpcError)
df.addBoth(self.gotErr, KRPC_ERROR_METHOD_UNKNOWN)
return df
def testMalformedRequest(self):
df = self.a.connectionForAddr(('127.0.0.1', 1181)).sendRequest('echo', {'msg' : "This is a test.", 'foo': 'bar'})
- df.addBoth(self.gotErr, KRPC_ERROR_MALFORMED_REQUEST)
+ df = self.failUnlessFailure(df, KrpcError)
+ df.addBoth(self.gotErr, KRPC_ERROR_MALFORMED_REQUEST, TypeError)
return df
- def gotErr(self, err, should_be):
- self.failUnlessEqual(err.value[0], should_be)
+ def gotErr(self, value, should_be, *errorTypes):
+ self.failUnlessEqual(value[0], should_be)
+ if errorTypes:
+ self.flushLoggedErrors(*errorTypes)
def testLongPackets(self):
df = self.a.connectionForAddr(('127.0.0.1', 1181)).sendRequest('values', {'length' : 1, 'num': 2000})