[tor-commits] [bridgedb/develop] Add unittests for bridgedb.captcha module.
isis at torproject.org
isis at torproject.org
Sun Mar 16 16:38:45 UTC 2014
commit 0395fb40a8621d3c996dcb06d70915cb84ab6fb6
Author: Isis Lovecruft <isis at torproject.org>
Date: Wed Mar 12 00:53:08 2014 +0000
Add unittests for bridgedb.captcha module.
---
lib/bridgedb/test/test_captcha.py | 237 +++++++++++++++++++++++++++++++++++++
1 file changed, 237 insertions(+)
diff --git a/lib/bridgedb/test/test_captcha.py b/lib/bridgedb/test/test_captcha.py
new file mode 100644
index 0000000..2e4a1cf
--- /dev/null
+++ b/lib/bridgedb/test/test_captcha.py
@@ -0,0 +1,237 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of BridgeDB, a Tor bridge distribution system.
+#
+# :authors: Isis Lovecruft 0xA3ADB67A2CDB8B35 <isis at torproject.org>
+# :copyright: (c) 2013-2014, Isis Lovecruft
+# (c) 2007-2014, The Tor Project, Inc.
+# :license: 3-Clause BSD, see LICENSE for licensing information
+
+"""Unittests for the :mod:`bridgedb.captcha` module."""
+
+
+import shutil
+import os
+
+from base64 import urlsafe_b64decode
+
+from twisted.trial import unittest
+
+from zope.interface import implementedBy
+from zope.interface import providedBy
+
+from bridgedb import captcha
+from bridgedb import crypto
+
+
+class CaptchaTests(unittest.TestCase):
+ """Tests for :class:`bridgedb.captcha.Captcha`."""
+
+ def test_implementation(self):
+ """Captcha class should implement ICaptcha interface."""
+ self.assertTrue(captcha.ICaptcha.implementedBy(captcha.Captcha))
+
+ def test_provider(self):
+ """ICaptcha should be provided by instances of Captcha."""
+ c = captcha.Captcha()
+ self.assertTrue(captcha.ICaptcha.providedBy(c))
+
+ def test_get(self):
+ """Captcha.get() should return None."""
+ c = captcha.Captcha()
+ self.assertIsNone(c.get())
+
+
+class ReCaptchaTests(unittest.TestCase):
+ """Tests for :class:`bridgedb.captcha.ReCaptcha`."""
+
+ def setUp(self):
+ self.c = captcha.ReCaptcha('publik', 'sekrit')
+
+ def test_init(self):
+ """Check the ReCaptcha class stored the private and public keys."""
+ self.assertEquals(self.c.privkey, 'sekrit')
+ self.assertEquals(self.c.pubkey, 'publik')
+
+ def test_get(self):
+ """Test get() method."""
+
+ # Force urllib2 to do anything less idiotic than the defaults:
+ envkey = 'HTTPS_PROXY'
+ oldkey = None
+ if os.environ.has_key(envkey):
+ oldkey = os.environ[envkey]
+ os.environ[envkey] = '127.0.0.1:9150'
+ # This stupid thing searches the environment for ``<protocol>_PROXY``
+ # variables, hence the above 'HTTPS_PROXY' env setting:
+ proxy = captcha.urllib2.ProxyHandler()
+ opener = captcha.urllib2.build_opener(proxy)
+ captcha.urllib2.install_opener(opener)
+
+ try:
+ # There isn't really a reliable way to test this function! :(
+ self.c.get()
+ except Exception as error:
+ reason = "ReCaptcha.get() test requires an active network "
+ reason += "connection.\nThis test failed with: %s" % error
+ raise unittest.SkipTest(reason)
+ else:
+ self.assertIsInstance(self.c.image, basestring)
+ self.assertIsInstance(self.c.challenge, basestring)
+ finally:
+ # Replace the original environment variable if there was one:
+ if oldkey:
+ os.environ[envkey] = oldkey
+ else:
+ os.environ.pop(envkey)
+
+ def test_get_noKeys(self):
+ """ReCaptcha.get() without API keys should fail."""
+ c = captcha.ReCaptcha()
+ self.assertRaises(captcha.ReCaptchaKeyError, c.get)
+
+
+class GimpCaptchaTests(unittest.TestCase):
+ """Tests for :class:`bridgedb.captcha.GimpCaptcha`."""
+
+ def setUp(self):
+ here = os.getcwd()
+ self.topDir = here.rstrip('_trial_temp')
+ self.cacheDir = os.path.join(self.topDir, 'captchas')
+ self.badCacheDir = os.path.join(here, 'capt')
+
+ # Get keys for testing or create them:
+ self.sekrit, self.publik = crypto.getRSAKey('test_gimpCaptcha_RSAkey')
+ self.hmacKey = crypto.getKey('test_gimpCaptcha_HMACkey')
+
+ def test_init_noSecretKey(self):
+ """Calling GimpCaptcha.__init__() without a secret key parameter should raise
+ a GimpCaptchaKeyError.
+ """
+ self.assertRaises(captcha.GimpCaptchaKeyError, captcha.GimpCaptcha,
+ None, self.publik, self.hmacKey, self.cacheDir)
+
+ def test_init_noPublicKey(self):
+ """__init__() without publicKey should raise a GimpCaptchaKeyError."""
+ self.assertRaises(captcha.GimpCaptchaKeyError, captcha.GimpCaptcha,
+ self.sekrit, None, self.hmacKey, self.cacheDir)
+
+ def test_init_noHMACKey(self):
+ """__init__() without hmacKey should raise a GimpCaptchaKeyError."""
+ self.assertRaises(captcha.GimpCaptchaKeyError, captcha.GimpCaptcha,
+ self.sekrit, self.publik, None, self.cacheDir)
+
+ def test_init_noCacheDir(self):
+ """__init__() without cacheDir should raise a GimpCaptchaKeyError."""
+ self.assertRaises(captcha.GimpCaptchaError, captcha.GimpCaptcha,
+ self.sekrit, self.publik, self.hmacKey, None)
+
+ def test_init_badCacheDir(self):
+ """GimpCaptcha with bad cacheDir should raise GimpCaptchaError."""
+ self.assertRaises(captcha.GimpCaptchaError, captcha.GimpCaptcha,
+ self.sekrit, self.publik, self.hmacKey,
+ self.cacheDir.rstrip('chas'))
+
+ def test_init(self):
+ """Test that __init__ correctly initialised all the values."""
+ c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ self.cacheDir)
+ self.assertIsNone(c.answer)
+ self.assertIsNone(c.image)
+ self.assertIsNone(c.challenge)
+
+ def test_createChallenge(self):
+ """createChallenge() should return the encrypted CAPTCHA answer."""
+ c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ self.cacheDir)
+ challenge = c.createChallenge('w00t')
+ self.assertIsInstance(challenge, basestring)
+
+ def test_createChallenge_base64(self):
+ """createChallenge() return value should be urlsafe base64-encoded."""
+ c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ self.cacheDir)
+ challenge = c.createChallenge('w00t')
+ decoded = urlsafe_b64decode(challenge)
+ self.assertTrue(decoded.find(';') >= 1)
+
+ def test_createChallenge_hmacValid(self):
+ """The HMAC in createChallenge() return value should be valid."""
+ c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ self.cacheDir)
+ challenge = c.createChallenge('ShouldHaveAValidHMAC')
+ decoded = urlsafe_b64decode(challenge)
+ hmac, orig = decoded.split(';', 1)
+ correctHMAC = crypto.getHMAC(self.hmacKey, orig)
+ self.assertTrue(hmac == correctHMAC)
+
+ def test_createChallenge_decryptedAnswerMatches(self):
+ """The HMAC in createChallenge() return value should be valid."""
+ c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ self.cacheDir)
+ answer = 'ThisAnswerShouldDecryptToThis'
+ challenge = c.createChallenge(answer)
+ decoded = urlsafe_b64decode(challenge)
+ hmac, orig = decoded.split(';', 1)
+ correctHMAC = crypto.getHMAC(self.hmacKey, orig)
+ self.assertEqual(hmac, correctHMAC)
+ decrypted = self.sekrit.decrypt(orig)
+ self.assertEqual(answer, decrypted)
+
+ def test_get(self):
+ """GimpCaptcha.get() should return image and challenge strings."""
+ c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ self.cacheDir)
+ image, challenge = c.get()
+ self.assertIsInstance(image, basestring)
+ self.assertIsInstance(challenge, basestring)
+
+ def test_get_emptyCacheDir(self):
+ """An empty cacheDir should raise GimpCaptchaError."""
+ os.makedirs(self.badCacheDir)
+ c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ self.badCacheDir)
+ self.assertRaises(captcha.GimpCaptchaError, c.get)
+ shutil.rmtree(self.badCacheDir)
+
+ def test_get_unreadableCaptchaFile(self):
+ """An unreadable CAPTCHA file should raise GimpCaptchaError."""
+ os.makedirs(self.badCacheDir)
+ badFile = os.path.join(self.badCacheDir, 'uNr34dA81e.jpg')
+ with open(badFile, 'w') as fh:
+ fh.write(' ')
+ fh.flush()
+ os.chmod(badFile, 0266)
+
+ c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ self.badCacheDir)
+ # This should hit the second `except:` clause in get():
+ self.assertRaises(captcha.GimpCaptchaError, c.get)
+ shutil.rmtree(self.badCacheDir)
+
+ def test_check(self):
+ """A correct answer and valid challenge should return True."""
+ c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ self.cacheDir)
+ image, challenge = c.get()
+ self.assertEquals(
+ c.check(challenge, c.answer, c.secretKey, c.hmacKey),
+ True)
+
+ def test_check_blankAnswer(self):
+ """A blank answer and valid challenge should return False."""
+ c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ self.cacheDir)
+ image, challenge = c.get()
+ self.assertEquals(
+ c.check(challenge, None, c.secretKey, c.hmacKey),
+ False)
+
+ def test_check_nonBase64(self):
+ """Valid answer and challenge with invalid base64 returns False."""
+ c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ self.cacheDir)
+ image, challenge = c.get()
+ self.assertEquals(
+ c.check(challenge.rstrip('=='), c.answer, c.secretKey, c.hmacKey),
+ False)
More information about the tor-commits
mailing list