Updated and added a lot of unittests.
authorCameron Dale <camrdale@gmail.com>
Fri, 11 Apr 2008 23:21:18 +0000 (16:21 -0700)
committerCameron Dale <camrdale@gmail.com>
Fri, 11 Apr 2008 23:21:18 +0000 (16:21 -0700)
Still need to add tests for the Peer and Cache Managers.

apt_p2p/HTTPServer.py
apt_p2p/PeerManager.py
apt_p2p/apt_p2p_conf.py
apt_p2p_Khashmir/db.py
apt_p2p_Khashmir/krpc.py

index f3d6de72525281df73660f35adc252f26d630414..cc6233ba955b192a31b15b94a46c620ede753bda 100644 (file)
@@ -1,13 +1,15 @@
 
 """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
@@ -197,10 +199,16 @@ class TopLevel(resource.Resource):
 
     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."""
@@ -248,6 +256,101 @@ class TopLevel(resource.Resource):
         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:
index dd39e41da1dbf8d9176a9c9035b2898fa8061a01..68a3c32a49304ab243840dbde2b4fbf09660b9d4 100644 (file)
@@ -681,60 +681,6 @@ class TestPeerManager(unittest.TestCase):
     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():
index e5c0f379d8761c0f16e5f7b6ff07a94b28f10975..fe56d7c9c456f7460ae517c38c116e7ff154021c 100644 (file)
@@ -14,6 +14,7 @@ import os, sys
 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."""
@@ -166,3 +167,46 @@ config = AptP2PConfigParser(DEFAULTS)
 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
index 8709970aee2890bb1de874947702b59370f2f3d5..a7962566cc5a07eb99c0744b65eb81389f8b45bc 100644 (file)
@@ -182,6 +182,7 @@ class TestDB(unittest.TestCase):
         
     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)
index ecedb02ccf938d3ef5b288f199ba4719704fc41d..47e7452f907e42baa755226e0b94db0abf7bd274 100644 (file)
@@ -570,16 +570,20 @@ class KRPCTests(unittest.TestCase):
 
     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})