[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[minion-cvs] Add tests for SMTP module and blacklisting. Also fix a ...
Update of /home/minion/cvsroot/src/minion/lib/mixminion
In directory moria.mit.edu:/tmp/cvs-serv18763/lib/mixminion
Modified Files:
test.py
Log Message:
Add tests for SMTP module and blacklisting. Also fix a time-dependant bug in path selection tests.
Index: test.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/test.py,v
retrieving revision 1.58
retrieving revision 1.59
diff -u -d -r1.58 -r1.59
--- test.py 4 Jan 2003 20:42:17 -0000 1.58
+++ test.py 5 Jan 2003 01:29:55 -0000 1.59
@@ -3195,8 +3195,8 @@
time.time()+24*60*60*30))
self.assert_(info.isValidAtPartOf(time.time(),
time.time()+24*60*60*30))
- self.assert_(not info.isValidAtPartOf(time.time()-25*60*60,
- time.time()-23*60*60))
+ self.assert_(not info.isValidAtPartOf(time.time()-40*60*60,
+ time.time()-39*60*60))
self.assert_(not info.isValidAtPartOf(time.time()+24*60*60*30,
time.time()+24*60*60*31))
@@ -3341,11 +3341,11 @@
self.failUnlessRaises(ConfigError, ServerDirectory, dBad)
# Bad digest.
dBad = re.compile(r"^DirectoryDigest: ........", re.M).sub(
- "DirectoryDigest: XXXXXXXX", d)
+ "DirectoryDigest: ZZZZZZZZ", d)
self.failUnlessRaises(ConfigError, ServerDirectory, dBad)
# Bad signature.
dBad = re.compile(r"^DirectorySignature: ........", re.M).sub(
- "Directory: XXXXXXXX", d)
+ "Directory: ZZZZZZZZ", d)
self.failUnlessRaises(ConfigError, ServerDirectory, dBad)
# Can we use messed-up spaces and line-endings?
@@ -3719,7 +3719,95 @@
======== TYPE III ANONYMOUS MESSAGE ENDS =========
"""
+EXAMPLE_ADDRESS_SET = """
+User freD
+User mr-ed
+# Comment
+Domain sally
+Domain HOGWARTS.k12
+# Another comment, followed by a blank line
+Subdomains deathstar.gov
+Subdomains selva-Oscura.it
+Domain selva-Oscura.it
+
+Address jim@sMith.com
+Pattern /nyet.*Nyet/
+
+"""
+
class ModuleTests(unittest.TestCase):
+ def testEmailAddressSet(self):
+ EmailAddressSet = mixminion.server.Modules.EmailAddressSet
+ def has(set, item, self=self):
+ self.assert_(isSMTPMailbox(item), "Invalid address "+item)
+ self.failUnless(set.contains(item), "Set should contain "+item)
+ def hasNo(set, item, self=self):
+ self.assert_(isSMTPMailbox(item), "Invalid address "+item)
+ self.failIf(set.contains(item), "Set should not contain "+item)
+
+ # Basic functionality: Match what we're supposed to match
+ set = EmailAddressSet(string=EXAMPLE_ADDRESS_SET)
+ for _ in 1,2:
+ has(set,"jim@smith.com")
+ has(set,"freD@fred.com") #(by user....)
+ has(set,"fred@x")
+ has(set,"fred@boba-fred")
+ has(set,"MR-ED@wilburs-barn.com")
+ has(set,"Fred@Fred")
+ has(set,"Fred@Sally") #(by domains and subdomains...)
+ has(set,"joe@SALLY")
+ has(set,"h.potter@hogwarts.K12")
+ has(set,"nobody@sally")
+ has(set,"dante@selva-oscura.it")
+ has(set,"dante@camin.selva-oscura.it")
+ has(set,"dante@nel.camin.selva-oscura.it")
+ has(set,"cushing@deathstar.gov")
+ has(set,"cushing@operational.deathstar.gov")
+ has(set,"cushing@fully.operational.deathstar.gov")
+ has(set,"nyet.jones@nyet.net")
+ has(set,"octavio.nyet.jones@nyet.net")
+ has(set,"octavio.jones@nyet.nyet.net")
+
+ # Basic tfunctinoality: Don't match anything else.
+ hasNo(set,"mojo@jojo.com")
+ hasNo(set,"mr-fred@wilburs-barn.com") # almost by user
+ hasNo(set,"joe@sally.com") # almost by domain...
+ hasNo(set,"joe@bob.sally.com")
+ hasNo(set,"joe@bob.sally")
+ hasNo(set,"dante@other.it")
+ hasNo(set,"cushing@gov")
+ hasNo(set,"cushing@deathstar.gov.mit.edu")
+ hasNo(set,"nyet.jones@net")
+ hasNo(set,"jones@nyet.net")
+
+ # Load from file, then try again!
+ fn = mix_mktemp()
+ writeFile(fn, EXAMPLE_ADDRESS_SET)
+ set = EmailAddressSet(fname=fn)
+
+ # Failing cases: invalid addresses needn't give a right answer, but
+ # we need to do something reasonable for invalid files.
+ def bad(s,self=self):
+ self.assertRaises(ConfigError,
+ mixminion.server.Modules.EmailAddressSet,
+ string=s)
+
+ bad("Address foo@bar@baz")
+ bad("Rumplestiltskin")
+ bad("bob@bob.com")
+ bad("user fred@bob")
+ bad("address foo")
+ bad("domain foo@")
+ bad("domain @foo")
+ bad("subdomains foo@bar")
+ bad("pattern a.*b")
+ bad("pattern /a.*b")
+ bad("pattern a.*b/")
+ bad("domain")
+ bad("user")
+ bad("pattern")
+ bad("subdomains")
+
def testMixmasterSMTP(self):
"""Check out the SMTP-Via-Mixmaster module. (We temporarily relace
os.spawnl with a stub function so that we don't actually send
@@ -3766,9 +3854,90 @@
undoReplacedAttributes()
clearReplacedFunctionCallLog()
+ def testDirectSMTP(self):
+ """Check out the SMTP module. (We temporarily relace sendSMTPMessage
+ with a stub function so that we don't actually send anything.)"""
+ blacklistFile = mix_mktemp()
+ writeFile(blacklistFile, "Domain wangafu.net\nUser fred\n")
+
+ manager = self.getManager("""[Delivery/SMTP]
+Enabled: yes
+SMTPServer: nowhere
+BlacklistFile: %s
+Message: Avast ye mateys! Prepare to be anonymized!
+ReturnAddress: yo.ho.ho@bottle.of.rum
+SubjectLine: Arr! This be a Type-III Anonymous Message
+ """ % blacklistFile)
+
+ module = manager.nameToModule["SMTP"]
+ queue = manager.queues["SMTP"]
+ queueMessage = queue.queueDeliveryMessage
+
+
+ # Make sure blacklist got read.
+ self.assert_(module.blacklist.contains("nobody@wangafu.net"))
+
+ # Stub out sendSMTPMessage.
+ replaceFunction(mixminion.server.Modules, 'sendSMTPMessage',
+ lambda *args: mixminion.server.Modules.DELIVER_OK)
+ try:
+ haiku = ("Hidden, we are free\n"+
+ "Free to speak, to free ourselves\n"+
+ "Free to hide no more.")
+
+ # Try queueing a valild message and sending it.
+ queueMessage((SMTP_TYPE, "users@everywhere", None), haiku)
+ self.assertEquals(getReplacedFunctionCallLog(), [])
+ queue.sendReadyMessages()
+ # Was sendSMTPMessage invoked correctly?
+ calls = getReplacedFunctionCallLog()
+ self.assertEquals(1, len(calls))
+ fn, args, _ = calls[0]
+ self.assertEquals("sendSMTPMessage", fn)
+ #server, toList, fromAddr, message
+ self.assertEquals(('nowhere',
+ ['users@everywhere'],
+ 'yo.ho.ho@bottle.of.rum'),
+ args[:3])
+ EXPECTED_SMTP_PACKET = """\
+To: users@everywhere
+From: yo.ho.ho@bottle.of.rum
+Subject: Arr! This be a Type-III Anonymous Message
+
+Avast ye mateys! Prepare to be anonymized!
+
+======= TYPE III ANONYMOUS MESSAGE BEGINS ========
+Hidden, we are free
+Free to speak, to free ourselves
+Free to hide no more.
+======== TYPE III ANONYMOUS MESSAGE ENDS =========\n"""
+ d = findFirstDiff(EXPECTED_SMTP_PACKET, args[3])
+ if d != -1:
+ print d, "near", repr(args[3][d-10:d+10])
+ self.assert_(EXPECTED_SMTP_PACKET == args[3])
+ clearReplacedFunctionCallLog()
+
+ # Now, try a bunch of messages that won't be delivered: one with
+ # an invalid address, and one with a blocked address.
+ try:
+ suspendLog()
+ queueMessage((SMTP_TYPE, "not.an.addr", None), haiku)
+ queueMessage((SMTP_TYPE, "blocked@wangafu.net", None), haiku)
+ queue.sendReadyMessages()
+ finally:
+ s = resumeLog()
+ self.assertEquals(1,s.count(
+ "Dropping message to blacklisted address 'blocked@wangafu.net'"))
+ self.assertEquals(1,s.count(
+ "Dropping SMTP message to invalid address 'not.an.addr'"))
+ self.assertEquals([], getReplacedFunctionCallLog())
+ finally:
+ undoReplacedAttributes()
+ clearReplacedFunctionCallLog()
+
def testMBOX(self):
- """Check out the MBOX module. (We temporarily relace sendSMTPMessage
- with a stub function so that we don't actually send anything."""
+ """Check out the MBOX module. (We temporarily relace sendSMTPMessage
+ with a stub function so that we don't actually send anything.)"""
# Configure the module
manager = self.getManager()
module = mixminion.server.Modules.MBoxModule()
@@ -3899,9 +4068,11 @@
self.assertEquals(1, queue.count())
self.assertEquals(5, len(os.listdir(dir)))
- def getManager(self):
+ def getManager(self, extraConfig=None):
d = mix_mktemp()
c = SERVER_CONFIG_SHORT % d
+ if extraConfig:
+ c += extraConfig
try:
suspendLog()
conf = mixminion.server.ServerConfig.ServerConfig(string=c)
@@ -4115,8 +4286,8 @@
"ReturnAddress: a@b.c\nRemoveContact: b@c.d\n") %(
addrf)
elif t == SMTP_TYPE:
- conf += ("[Delivery/SMTP-Via-Mixmaster]\nEnabled: yes\n"+
- "MixCommand: /bin/ls\nServer: foobar\n")
+ conf += ("[Delivery/SMTP]\nEnabled: yes\n"+
+ "ReturnAddress: a@b.c\n")
else:
raise MixFatalError("Unrecognized type: %04x"%t)
try:
@@ -4309,6 +4480,10 @@
d[item] = 1
return len(d) == len(lst)
+ # Override ks.DEFAULT_REQUIRED_LIFETIME so we don't need to
+ # explicitly specify a really early endAt all the time.
+ ks.DEFAULT_REQUIRED_LIFETIME = 1
+
suspendLog()
joe = edesc["Joe"]
alice = edesc["Alice"]
@@ -4362,56 +4537,65 @@
neq(p[1].getNickname(), "Alice")
neq(p[1].getNickname(), "Joe")
# 2b. With 3 <= servers < length
- p = ks.getPath(length=9)
+ ks2 = mixminion.ClientMain.ClientKeystore(mix_mktemp())
+ ks2.importFromFile(os.path.join(impdirname, "Joe0"))
+ ks2.importFromFile(os.path.join(impdirname, "Alice0"))
+ ks2.importFromFile(os.path.join(impdirname, "Lisa1"))
+ ks2.importFromFile(os.path.join(impdirname, "Bob0"))
+
+ p = ks2.getPath(length=9)
eq(9, len(p))
self.failIf(nRuns([s.getNickname() for s in p]))
- p = ks.getPath(startServers=("Joe",),endServers=("Joe",),length=8)
+ p = ks2.getPath(startServers=("Joe",),endServers=("Joe",),
+ length=8)
self.failIf(nRuns([s.getNickname() for s in p]))
eq(8, len(p))
self.assertSameSD(joe[0], p[0])
self.assertSameSD(joe[0], p[-1])
- p = ks.getPath(startServers=("Joe",),length=7)
+ p = ks2.getPath(startServers=("Joe",),length=7)
self.failIf(nRuns([s.getNickname() for s in p]))
eq(7, len(p))
self.assertSameSD(joe[0], p[0])
- p = ks.getPath(endServers=("Joe",),length=7)
+ p = ks2.getPath(endServers=("Joe",),length=7)
self.failIf(nRuns([s.getNickname() for s in p]))
eq(7, len(p))
self.assertSameSD(joe[0], p[-1])
-
+
# 2c. With 2 servers
- p = ks.getPath(length=4, startAt=now-9*oneDay)
+ ks2.expungeByNickname("Alice")
+ ks2.expungeByNickname("Bob")
+ p = ks2.getPath(length=4)
self.failIf(nRuns([s.getNickname() for s in p]) > 1)
- p = ks.getPath(length=4,startServers=("Joe",),startAt=now-9*oneDay)
- self.failIf(nRuns([s.getNickname() for s in p]) > 2)
+ p = ks2.getPath(length=4,startServers=("Joe",))
- p = ks.getPath(length=4, endServers=("Joe",), startAt=now-9*oneDay)
+ self.failIf(nRuns([s.getNickname() for s in p]) > 2)
+ p = ks2.getPath(length=4, endServers=("Joe",))
self.failIf(nRuns([s.getNickname() for s in p]) > 1)
- p = ks.getPath(length=6, endServers=("Joe",), startAt=now-9*oneDay)
+ p = ks2.getPath(length=6, endServers=("Joe",))
self.failIf(nRuns([s.getNickname() for s in p]) > 1)
# 2d. With only 1.
- p = ks.getPath(length=4, startAt=now-11*oneDay)
+ ks2.expungeByNickname("Lisa")
+ p = ks2.getPath(length=4)
eq(len(p), 2)
- p = ks.getPath(length=4,
- startServers=("Joe",),startAt=now-11*oneDay)
+ p = ks2.getPath(length=4, startServers=("Joe",))
eq(len(p), 3)
- p = ks.getPath(length=4, endServers=("Joe",),startAt=now-11*oneDay)
+ p = ks2.getPath(length=4, endServers=("Joe",))
eq(len(p), 2)
# 2e. With 0
self.assertRaises(MixError, ks.getPath,
- length=4, startAt=now+100*oneDay)
+ length=4, startAt=now+100*oneDay)
finally:
s = resumeLog()
- self.assertEquals(4, s.count("Not enough servers for distinct"))
- self.assertEquals(4, s.count("to avoid same-server hops"))
- self.assertEquals(3, s.count("Only one relay known"))
+ self.assertEquals(4, s.count("Not enough servers for distinct"))
+ self.assertEquals(4, s.count("to avoid same-server hops"))
+ self.assertEquals(3, s.count("Only one relay known"))
# 3. With capabilities.
p = ks.getPath(length=5, endCap="smtp", midCap="relay")
@@ -4645,7 +4829,7 @@
parseFails("0xZZ:zymurgy") # Bad hex literal
parseFails("0xZZ") # Bad hex literal, no data.
parseFails("0x9999") # No data
- parseFails("0xFFFFF:zymurgy") # Hex literal out of range
+ parseFails("0xFEEEF:zymurgy") # Hex literal out of range
def testMixminionClient(self):
# Create and configure a MixminionClient object...
@@ -4726,7 +4910,7 @@
# Empty path...
self.assertRaises(MixError,
client.generateForwardMessage,
- parseAddress("0xFFFF:zed"),
+ parseAddress("0xFFFE:zed"),
"Z", [], [Alice])
# Temporarily replace BlockingClientConnection so we can try the client
@@ -4791,6 +4975,11 @@
suite = unittest.TestSuite()
loader = unittest.TestLoader()
tc = loader.loadTestsFromTestCase
+
+ if 0:
+ suite.addTest(tc(ClientMainTests))
+ suite.addTest(tc(ModuleTests))
+ return suite
suite.addTest(tc(MiscTests))
suite.addTest(tc(MinionlibCryptoTests))