[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[minion-cvs] Add test for connection timeout; add tests for corrupt ...
Update of /home/minion/cvsroot/src/minion/lib/mixminion
In directory moria.mit.edu:/tmp/cvs-serv3863/lib/mixminion
Modified Files:
test.py
Log Message:
Add test for connection timeout; add tests for corrupt whitespace and newlines
in config files and serverinfos; add tests for serverinfo pickleability.
Index: test.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/test.py,v
retrieving revision 1.50
retrieving revision 1.51
diff -u -d -r1.50 -r1.51
--- test.py 20 Dec 2002 23:52:07 -0000 1.50
+++ test.py 29 Dec 2002 20:34:36 -0000 1.51
@@ -192,17 +192,15 @@
# Sample 1000 evenly spaced points, making sure...
for t in xrange(10, now, floorDiv(now, 1000)):
yyyy,MM,dd,hh,mm,ss = time.gmtime(t)[:6]
- # 1. That mkgmtime inverts time.gmtime.
- self.assertEquals(t, mkgmtime(yyyy,MM,dd,hh,mm,ss))
- # 2. That previousMidnight returns the same day, at midnight.
+ # 1. That previousMidnight returns the same day, at midnight.
pm = previousMidnight(t)
yyyy2,MM2,dd2,hh2,mm2,ss2 = time.gmtime(pm)[:6]
self.assertEquals((yyyy2,MM2,dd2), (yyyy,MM,dd))
self.assertEquals((0,0,0), (hh2,mm2,ss2))
self.failUnless(pm <= t and 0 <= (t-pm) <= max_sec_per_day)
- # 3. That previousMidnight is repeatable
+ # 2. That previousMidnight is repeatable
self.assertEquals(previousMidnight(t), pm)
- # 4. That previousMidnight is idempotent
+ # 3. That previousMidnight is idempotent
self.assertEquals(previousMidnight(pm), pm)
def test_isSMTPMailbox(self):
@@ -496,6 +494,9 @@
s = cPickle.dumps(k512)
self.assertEquals(cPickle.loads(s).get_public_key(),
k512.get_public_key())
+ s = cPickle.dumps(k512, 1)
+ self.assertEquals(cPickle.loads(s).get_public_key(),
+ k512.get_public_key())
def test_trng(self):
# Make sure that the true rng is at least superficially ok.
@@ -2379,6 +2380,9 @@
def testNonblockingTransmission(self):
self.doTest(self._testNonblockingTransmission)
+ def testTimeout(self):
+ self.doTest(self._testTimeout)
+
def _testBlockingTransmission(self):
server, listener, messagesIn, keyid = _getMMTPServer()
self.listener = listener
@@ -2395,9 +2399,9 @@
server.process(0.1)
t.join()
- for _ in xrange(10):
+ for _ in xrange(3):
server.process(0.1)
-
+
self.failUnless(messagesIn == messages)
# Now, with bad keyid.
@@ -2417,6 +2421,7 @@
self.listener = listener
self.server = server
+ tlscon = mixminion.server.MMTPServer.SimpleTLSConnection
messages = ["helloxxx"*4096, "helloyyy"*4096]
async = mixminion.server.MMTPServer.AsyncServer()
clientcon = mixminion.server.MMTPServer.MMTPClientConnection(
@@ -2427,18 +2432,28 @@
while not clientcon.isShutdown():
async.process(2)
+
server.process(0.1)
+ startTime = time.time()
t = threading.Thread(None, clientThread)
+ c = None
t.start()
while len(messagesIn) < 2:
+ if c is None and len(server.readers) > 1:
+ c = [ c for c in server.readers.values() if
+ isinstance(c, tlscon) ]
server.process(0.1)
while t.isAlive():
server.process(0.1)
t.join()
+ endTime = time.time()
self.assertEquals(len(messagesIn), len(messages))
self.failUnless(messagesIn == messages)
+ self.failUnless(c is not None)
+ self.failUnless(len(c) == 1)
+ self.failUnless(startTime <= c[0].lastActivity <= endTime)
# Again, with bad keyid.
clientcon = mixminion.server.MMTPServer.MMTPClientConnection(
@@ -2461,11 +2476,85 @@
finally:
resumeLog() #unsuppress warning
+ def _testTimeout(self):
+ server, listener, messagesIn, keyid = _getMMTPServer()
+ self.listener = listener
+ self.server = server
+
+ # This is a little tricky. We want to test connection timeouts, so we
+ # concoct a fake list object that blocks before returning its second
+ # element so that we can make MMTPClient.sendMessages pause for a
+ # while.
+ class SlowMessageList:
+ def __init__(self):
+ self.pausing = 50
+ def __getitem__(self, i):
+ if i == 0:
+ return "helloxxx"*4096
+ elif i == 1:
+ # We use a counter here so that we can make the thread
+ # holding this list end quickly when we want it to.
+ while self.pausing > 0:
+ time.sleep(0.1)
+ self.pausing -= 0.1
+ return "helloyyy"*4096
+ else:
+ raise IndexError
+
+ # This function wraps MMTPClient.sendMessages, but catches exceptions.
+ # Since we're going to run this function in a thread, we pass the
+ # exception back through a list argument.
+ def sendAndCaptureException(lst, *args):
+ try:
+ mixminion.MMTPClient.sendMessages(*args)
+ except:
+ lst.append(sys.exc_info())
+
+ # Manually set the server's timeout threshold to 600 msec.
+ server._timeout = 0.6
+ server.process(0.1)
+ excList = []
+ msgList = SlowMessageList()
+ t = threading.Thread(None,
+ sendAndCaptureException,
+ args=(excList, "127.0.0.1", TEST_PORT, keyid, msgList))
+ t.start()
+ timedOut = 0 # flag: have we really timed out?
+ try:
+ suspendLog() # stop logging, but wait for the timeout message.
+ while len(messagesIn) < 2:
+ server.process(0.1)
+ # If the number of connections changes around the call
+ # to tryTimeout, the timeout has occurred.
+ nConnections = len(server.readers)+len(server.writers)
+ server.tryTimeout(time.time())
+ if len(server.readers)+len(server.writers) < nConnections:
+ timedOut = 1
+ break
+ # Did we really time out the connection, or did we end normally?
+ self.assert_(timedOut)
+ finally:
+ logMessage = resumeLog()
+ # Did we log the timeout?
+ self.assert_(stringContains(logMessage, "timed out"))
+ # Was the one message we expected in fact transmitted?
+ self.assertEquals([messagesIn[0]], ["helloxxx"*4096])
+
+ # Now stop the transmitting thread. It will notice that its
+ # connection has been forcibly closed.
+ msgList.pausing = 0
+ t.join()
+ # Was an exception raised?
+ self.assertEquals(1, len(excList))
+ # Was it the right exception?
+ self.assert_(isinstance(excList[0][1], _ml.TLSClosed))
+
+ for _ in xrange(3):
+ server.process(0.1)
#----------------------------------------------------------------------
# Config files
-
class TestConfigFile(_ConfigFile):
_syntax = { 'Sec1' : {'__SECTION__': ('REQUIRE', None, None),
'Foo': ('REQUIRE', None, None),
@@ -2661,8 +2750,10 @@
# Base64
self.assertEquals(C._parseBase64(" YW\nJj"), "abc")
+ self.assertEquals(C._parseBase64(" Y W\nJ j"), "abc")
# Hex
self.assertEquals(C._parseHex(" C0D0"), "\xC0\xD0")
+ self.assertEquals(C._parseHex(" C0\n D 0"), "\xC0\xD0")
# Date
tm = C._parseDate("2002/05/30")
self.assertEquals(time.gmtime(tm)[:6], (2002,5,30,0,0,0))
@@ -2835,6 +2926,15 @@
])
eq(info['Delivery/MBOX'].get('Version'), None)
+ # Now check whether we still validate the same after some corruption
+ self.assert_(inf.startswith("[Server]\n"))
+ self.assert_(inf.endswith("\n"))
+ self.assert_(stringContains(inf, "b.c\n"))
+ inf2 = inf.replace("[Server]\n", "[Server] \r")
+ inf2 = inf2.replace("b.c\n", "b.c\r\n")
+ inf2 = inf2.replace("0.1\n", "0.1 \n")
+ mixminion.ServerInfo.ServerInfo(string=inf2)
+
# Now make sure everything was saved properly
keydir = os.path.join(d, "key_key1")
eq(inf, readFile(os.path.join(keydir, "ServerDesc")))
@@ -2856,6 +2956,13 @@
eq(info['Server']['Digest'], x)
eq(x, Crypto.pk_check_signature(info['Server']['Signature'],
identityPK))
+
+ # Now check pickleability
+ pickled = cPickle.dumps(info, 1)
+ loaded = cPickle.loads(pickled)
+ eq(info['Server']['Digest'], loaded['Server']['Digest'])
+ eq(info['Server']['Identity'].get_public_key(),
+ loaded['Server']['Identity'].get_public_key())
# Now with a shorter configuration
try: