diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/leap/__init__.py | 2 | ||||
-rw-r--r-- | src/leap/common/__init__.py | 9 | ||||
-rw-r--r-- | src/leap/common/__init__.pyc | bin | 0 -> 414 bytes | |||
-rw-r--r-- | src/leap/common/certs.py | 179 | ||||
-rw-r--r-- | src/leap/common/certs.pyc | bin | 0 -> 4951 bytes | |||
-rw-r--r-- | src/leap/common/check.py | 61 | ||||
-rw-r--r-- | src/leap/common/check.pyc | bin | 0 -> 1631 bytes | |||
-rw-r--r-- | src/leap/common/files.py | 85 | ||||
-rw-r--r-- | src/leap/common/files.pyc | bin | 0 -> 2009 bytes | |||
-rw-r--r-- | src/leap/common/testing/__init__.py | 0 | ||||
-rw-r--r-- | src/leap/common/testing/basetest.py | 100 | ||||
-rw-r--r-- | src/leap/common/testing/cacert.pem | 23 | ||||
-rw-r--r-- | src/leap/common/testing/https_server.py | 87 | ||||
-rw-r--r-- | src/leap/common/testing/leaptestscert.pem | 84 | ||||
-rw-r--r-- | src/leap/common/testing/leaptestskey.pem | 27 | ||||
-rw-r--r-- | src/leap/common/testing/test_basetest.py | 109 |
16 files changed, 766 insertions, 0 deletions
diff --git a/src/leap/__init__.py b/src/leap/__init__.py new file mode 100644 index 0000000..3ad9513 --- /dev/null +++ b/src/leap/__init__.py @@ -0,0 +1,2 @@ +from pkgutil import extend_path +__path__ = extend_path(__path__, __name__) diff --git a/src/leap/common/__init__.py b/src/leap/common/__init__.py new file mode 100644 index 0000000..a70a9a8 --- /dev/null +++ b/src/leap/common/__init__.py @@ -0,0 +1,9 @@ +import logging +logger = logging.getLogger(__name__) + +try: + import pygeoip + HAS_GEOIP = True +except ImportError: + logger.debug('PyGeoIP not found. Disabled Geo support.') + HAS_GEOIP = False diff --git a/src/leap/common/__init__.pyc b/src/leap/common/__init__.pyc Binary files differnew file mode 100644 index 0000000..fb08022 --- /dev/null +++ b/src/leap/common/__init__.pyc diff --git a/src/leap/common/certs.py b/src/leap/common/certs.py new file mode 100644 index 0000000..4cb70dd --- /dev/null +++ b/src/leap/common/certs.py @@ -0,0 +1,179 @@ +# -*- coding: utf-8 -*- +# certs.py +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Implements cert checks and helpers +""" + +import os +import time +import logging + +from OpenSSL import crypto +from dateutil.parser import parse as dateparse + +from leap.common.check import leap_assert + +logger = logging.getLogger(__name__) + + +def get_cert_from_string(string): + """ + Returns the x509 from the contents of this string + + @param string: certificate contents as downloaded + @type string: str + + @return: x509 or None + """ + leap_assert(string, "We need something to load") + + x509 = None + try: + x509 = crypto.load_certificate(crypto.FILETYPE_PEM, string) + except Exception as e: + logger.error("Something went wrong while loading the certificate: %r" + % (e,)) + return x509 + + +def get_privatekey_from_string(string): + """ + Returns the private key from the contents of this string + + @param string: private key contents as downloaded + @type string: str + + @return: private key or None + """ + leap_assert(string, "We need something to load") + + pkey = None + try: + pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, string) + except Exception as e: + logger.error("Something went wrong while loading the certificate: %r" + % (e,)) + return pkey + + +def get_digest(cert_data, method): + """ + Returns the digest for the cert_data using the method specified + + @param cert_data: certificate data in string form + @type cert_data: str + @param method: method to be used for digest + @type method: str + + @rtype: str + """ + x509 = get_cert_from_string(cert_data) + digest = x509.digest(method).replace(":", "").lower() + + return digest + + +def can_load_cert_and_pkey(string): + """ + Loads certificate and private key from a buffer, returns True if + everything went well, False otherwise + + @param string: buffer containing the cert and private key + @type string: str or any kind of buffer + + @rtype: bool + """ + can_load = True + + try: + cert = get_cert_from_string(string) + key = get_privatekey_from_string(string) + + leap_assert(cert, 'The certificate could not be loaded') + leap_assert(key, 'The private key could not be loaded') + except Exception as e: + can_load = False + logger.error("Something went wrong while trying to load " + "the certificate: %r" % (e,)) + + return can_load + + +def is_valid_pemfile(cert): + """ + Checks that the passed string is a valid pem certificate + + @param cert: String containing pem content + @type cert: str + + @rtype: bool + """ + leap_assert(cert, "We need a cert to load") + + return can_load_cert_and_pkey(cert) + + +def get_cert_time_boundaries(certfile): + """ + Returns the time boundaries for the certificate saved in certfile + + @param certfile: path to certificate + @type certfile: str + + @rtype: tuple (from, to) + """ + cert = get_cert_from_string(certfile) + leap_assert(cert, 'There was a problem loading the certificate') + + fromts, tots = (cert.get_notBefore(), cert.get_notAfter()) + from_, to_ = map( + lambda ts: time.gmtime(time.mktime(dateparse(ts).timetuple())), + (fromts, tots)) + return from_, to_ + + +def should_redownload(certfile, now=time.gmtime): + """ + Returns True if any of the checks don't pass, False otherwise + + @param certfile: path to certificate + @type certfile: str + @param now: current date function, ONLY USED FOR TESTING + + @rtype: bool + """ + exists = os.path.isfile(certfile) + + if not exists: + return True + + certdata = None + try: + with open(certfile, "r") as f: + certdata = f.read() + if not is_valid_pemfile(certdata): + return True + except: + return True + + valid_from, valid_to = get_cert_time_boundaries(certdata) + + if not (valid_from < now() < valid_to): + return True + + return False diff --git a/src/leap/common/certs.pyc b/src/leap/common/certs.pyc Binary files differnew file mode 100644 index 0000000..eecff8b --- /dev/null +++ b/src/leap/common/certs.pyc diff --git a/src/leap/common/check.py b/src/leap/common/check.py new file mode 100644 index 0000000..9787341 --- /dev/null +++ b/src/leap/common/check.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +# check.py +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Set of functions to help checking situations +""" +import logging +import inspect +import traceback + + +logger = logging.getLogger(__name__) + + +def leap_assert(condition, message=""): + """ + Asserts the condition and displays the message if that's not + met. It also logs the error and its backtrace. + + @param condition: condition to check + @type condition: bool + @param message: message to display if the condition isn't met + @type message: str + """ + if not condition: + logger.error("Bug: %s" % (message,)) + try: + frame = inspect.currentframe() + stack_trace = traceback.format_stack(frame) + logger.error(''.join(stack_trace)) + except Exception as e: + logger.error("Bug in leap_assert: %r" % (e,)) + assert condition, message + + +def leap_assert_type(var, expectedType): + """ + Helper assert check for a variable's expected type + + @param var: variable to check + @type var: any + @param expectedType: type to check agains + @type expectedType: type + """ + leap_assert(isinstance(var, expectedType), + "Expected type %r instead of %r" % + (expectedType, type(var))) diff --git a/src/leap/common/check.pyc b/src/leap/common/check.pyc Binary files differnew file mode 100644 index 0000000..7c48489 --- /dev/null +++ b/src/leap/common/check.pyc diff --git a/src/leap/common/files.py b/src/leap/common/files.py new file mode 100644 index 0000000..7c878e1 --- /dev/null +++ b/src/leap/common/files.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +# files.py +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Implements file helper methods +""" + +import os +import stat +import logging +import time +import errno + +logger = logging.getLogger(__name__) + + +def check_and_fix_urw_only(cert): + """ + Test for 600 mode and try to set it if anything different found + + Might raise OSError + + @param cert: Certificate path + @type cert: str + """ + mode = stat.S_IMODE(os.stat(cert).st_mode) + + if mode != int('600', 8): + try: + logger.warning('Bad permission on %s attempting to set 600' % + (cert,)) + os.chmod(cert, stat.S_IRUSR | stat.S_IWUSR) + except OSError: + logger.error('Error while trying to chmod 600 %s' % + cert) + raise + + +def get_mtime(filename): + """ + Returns the modified time or None if the file doesn't exist + + @param filename: path to check + @type filename: str + + @rtype: str + """ + try: + mtime = time.ctime(os.path.getmtime(filename)) + " GMT" + return mtime + except OSError: + return None + + +def mkdir_p(path): + """ + Creates the path and all the intermediate directories that don't + exist + + Might raise OSError + + @param path: path to create + @type path: str + """ + try: + os.makedirs(path) + except OSError as exc: + if exc.errno == errno.EEXIST and os.path.isdir(path): + pass + else: + raise diff --git a/src/leap/common/files.pyc b/src/leap/common/files.pyc Binary files differnew file mode 100644 index 0000000..5f0273c --- /dev/null +++ b/src/leap/common/files.pyc diff --git a/src/leap/common/testing/__init__.py b/src/leap/common/testing/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/leap/common/testing/__init__.py diff --git a/src/leap/common/testing/basetest.py b/src/leap/common/testing/basetest.py new file mode 100644 index 0000000..2359754 --- /dev/null +++ b/src/leap/common/testing/basetest.py @@ -0,0 +1,100 @@ +# -*- coding: utf-8 -*- +# leap.common.testing.basetest.py +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +Common testing facilities +""" +import os +import platform +import shutil +import tempfile + +try: + import unittest2 as unittest +except ImportError: + import unittest + +from leap.common.files import mkdir_p, check_and_fix_urw_only + +_system = platform.system() + + +class BaseLeapTest(unittest.TestCase): + """ + Base Leap TestCase + """ + + __name__ = "leap_test" + + @classmethod + def setUpClass(cls): + cls.old_path = os.environ['PATH'] + cls.old_home = os.environ['HOME'] + cls.tempdir = tempfile.mkdtemp(prefix="leap_tests-") + cls.home = cls.tempdir + bin_tdir = os.path.join( + cls.tempdir, + 'bin') + os.environ["PATH"] = bin_tdir + os.environ["HOME"] = cls.tempdir + + @classmethod + def tearDownClass(cls): + os.environ["PATH"] = cls.old_path + os.environ["HOME"] = cls.old_home + # safety check + assert cls.tempdir.startswith('/tmp/leap_tests-') + shutil.rmtree(cls.tempdir) + + # you have to override these methods + # this way we ensure we did not put anything + # here that you can forget to call. + + def setUp(self): + raise NotImplementedError("abstract base class") + + def tearDown(self): + raise NotImplementedError("abstract base class") + + # + # helper methods + # + + def get_tempfile(self, filename): + return os.path.join(self.tempdir, filename) + + def _missing_test_for_plat(self, do_raise=False): + if do_raise: + raise NotImplementedError( + "This test is not implemented " + "for the running platform: %s" % + _system) + + def touch(self, filepath): + folder, filename = os.path.split(filepath) + if not os.path.isdir(folder): + mkdir_p(folder) + # XXX should move to test_basetest + self.assertTrue(os.path.isdir(folder)) + + with open(filepath, 'w') as fp: + fp.write(' ') + + # XXX should move to test_basetest + self.assertTrue(os.path.isfile(filepath)) + + def chmod600(self, filepath): + check_and_fix_urw_only(filepath) diff --git a/src/leap/common/testing/cacert.pem b/src/leap/common/testing/cacert.pem new file mode 100644 index 0000000..6989c48 --- /dev/null +++ b/src/leap/common/testing/cacert.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID1TCCAr2gAwIBAgIJAOv0BS09D8byMA0GCSqGSIb3DQEBBQUAMIGAMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKY3liZXJzcGFjZTEnMCUGA1UECgweTEVBUCBFbmNy +eXB0aW9uIEFjY2VzcyBQcm9qZWN0MRYwFAYDVQQDDA10ZXN0cy1sZWFwLnNlMRsw +GQYJKoZIhvcNAQkBFgxpbmZvQGxlYXAuc2UwHhcNMTIwODMxMTYyNjMwWhcNMTUw +ODMxMTYyNjMwWjCBgDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCmN5YmVyc3BhY2Ux +JzAlBgNVBAoMHkxFQVAgRW5jcnlwdGlvbiBBY2Nlc3MgUHJvamVjdDEWMBQGA1UE +AwwNdGVzdHMtbGVhcC5zZTEbMBkGCSqGSIb3DQEJARYMaW5mb0BsZWFwLnNlMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1pU7OU+abrUXFZwp6X0LlF0f +xQvC1Nmr5sFH7N9RTu3bdwY2t57ECP2TPkH6+x7oOvCTgAMxIE1scWEEkfgKViqW +FH/Om1UW1PMaiDYGtFuqEuxM95FvaYxp2K6rzA37WNsedA28sCYzhRD+/5HqbCNT +3rRS2cPaVO8kXI/5bgd8bUk3009pWTg4SvTtOW/9MWJbBH5f5JWmMn7Ayt6hIdT/ +E6npofEK/UCqAlEscARYFXSB/F8nK1whjo9mGFjMUd7d/25UbFHqOk4K7ishD4DH +F7LaS84rS+Sjwn3YtDdDQblGghJfz8X1AfPSGivGnvLVdkmMF9Y2hJlSQ7+C5wID +AQABo1AwTjAdBgNVHQ4EFgQUnpJEv4FnlqKbfm7mprudKdrnOAowHwYDVR0jBBgw +FoAUnpJEv4FnlqKbfm7mprudKdrnOAowDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B +AQUFAAOCAQEAGW66qwdK/ATRVZkTpI2sgi+2dWD5tY4VyZuJIrRwfXsGPeVvmdsa +zDmwW5dMkth1Of5yO6o7ijvUvfnw/UCLNLNICKZhH5G0DHstfBeFc0jnP2MqOZCp +puRGPBlO2nxUCvoGcPRUKGQK9XSYmxcmaSFyzKVDMLnmH+Lakj5vaY9a8ZAcZTz7 +T5qePxKAxg+RIlH8Ftc485QP3fhqPYPrRsL3g6peiqCvIRshoP1MSoh19boI+1uX +wHQ/NyDkL5ErKC5JCSpaeF8VG1ek570kKWQLuQAbnlXZw+Sqfu35CIdizHaYGEcx +xA8oXH4L2JaT2x9GKDSpCmB2xXy/NVamUg== +-----END CERTIFICATE----- diff --git a/src/leap/common/testing/https_server.py b/src/leap/common/testing/https_server.py new file mode 100644 index 0000000..08d5089 --- /dev/null +++ b/src/leap/common/testing/https_server.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- +# leap.common.testing.https_server.py +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +A simple HTTPS server to be used in tests +""" +from BaseHTTPServer import HTTPServer +import os +import ssl +import SocketServer +import threading +import unittest + +_where = os.path.split(__file__)[0] + + +def where(filename): + return os.path.join(_where, filename) + + +class HTTPSServer(HTTPServer): + def server_bind(self): + SocketServer.TCPServer.server_bind(self) + self.socket = ssl.wrap_socket( + self.socket, server_side=True, + certfile=where("leaptestscert.pem"), + keyfile=where("leaptestskey.pem"), + ca_certs=where("cacert.pem"), + ssl_version=ssl.PROTOCOL_SSLv23) + + +class TestServerThread(threading.Thread): + def __init__(self, test_object, request_handler): + threading.Thread.__init__(self) + self.request_handler = request_handler + self.test_object = test_object + + def run(self): + self.server = HTTPSServer(('localhost', 0), self.request_handler) + host, port = self.server.socket.getsockname() + self.test_object.HOST, self.test_object.PORT = host, port + self.test_object.server_started.set() + self.test_object = None + try: + self.server.serve_forever(0.05) + finally: + self.server.server_close() + + def stop(self): + self.server.shutdown() + + +class BaseHTTPSServerTestCase(unittest.TestCase): + """ + derived classes need to implement a request_handler + """ + def setUp(self): + self.server_started = threading.Event() + self.thread = TestServerThread(self, self.request_handler) + self.thread.start() + self.server_started.wait() + + def tearDown(self): + self.thread.stop() + + def get_server(self): + host, port = self.HOST, self.PORT + if host == "127.0.0.1": + host = "localhost" + return "%s:%s" % (host, port) + + +if __name__ == "__main__": + unittest.main() diff --git a/src/leap/common/testing/leaptestscert.pem b/src/leap/common/testing/leaptestscert.pem new file mode 100644 index 0000000..65596b1 --- /dev/null +++ b/src/leap/common/testing/leaptestscert.pem @@ -0,0 +1,84 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + eb:f4:05:2d:3d:0f:c6:f3 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, ST=cyberspace, O=LEAP Encryption Access Project, CN=tests-leap.se/emailAddress=info@leap.se + Validity + Not Before: Aug 31 16:30:17 2012 GMT + Not After : Aug 31 16:30:17 2013 GMT + Subject: C=US, ST=cyberspace, L=net, O=LEAP Encryption Access Project, CN=localhost/emailAddress=info@leap.se + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bc:f1:c4:05:ce:4b:d5:9b:9a:fa:c1:a5:0c:89: + 15:7e:05:69:b6:a4:62:38:3a:d6:14:4a:36:aa:3c: + 31:70:54:2e:bf:7d:05:19:ad:7b:0c:a9:a6:7d:46: + be:83:62:cb:ea:b9:48:6c:7d:78:a0:10:0b:ad:8a: + 74:7a:b8:ff:32:85:64:36:90:dc:38:dd:90:6e:07: + 82:70:ae:5f:4e:1f:f4:46:98:f3:98:b4:fa:08:65: + bf:d6:ec:a9:ba:7e:a8:f0:40:a2:d0:1a:cb:e6:fc: + 95:c5:54:63:92:5b:b8:0a:36:cc:26:d3:2b:ad:16: + ff:49:53:f4:65:7c:64:27:9a:f5:12:75:11:a5:0c: + 5a:ea:1e:e4:31:f3:a6:2b:db:0e:4a:5d:aa:47:3a: + f0:5e:2a:d5:6f:74:b6:f8:bc:9a:73:d0:fa:8a:be: + a8:69:47:9b:07:45:d9:b5:cd:1c:9b:c5:41:9a:65: + cc:99:a0:bd:bf:b5:e8:9f:66:5f:69:c9:6d:c8:68: + 50:68:74:ae:8e:12:7e:9c:24:4f:dc:05:61:b7:8a: + 6d:2a:95:43:d9:3f:fe:d8:c9:a7:ae:63:cd:30:d5: + 95:84:18:2d:12:b5:2d:a6:fe:37:dd:74:b8:f8:a5: + 59:18:8f:ca:f7:ae:63:0d:9d:66:51:7d:9c:40:48: + 9b:a1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + B2:50:B4:C6:38:8F:BA:C4:3B:69:4C:6B:45:7C:CF:08:48:36:02:E0 + X509v3 Authority Key Identifier: + keyid:9E:92:44:BF:81:67:96:A2:9B:7E:6E:E6:A6:BB:9D:29:DA:E7:38:0A + + Signature Algorithm: sha1WithRSAEncryption + aa:ab:d4:27:e3:cb:42:05:55:fd:24:b3:e5:55:7d:fb:ce:6c: + ff:c7:96:f0:7d:30:a1:53:4a:04:eb:a4:24:5e:96:ee:65:ef: + e5:aa:08:47:9d:aa:95:2a:bb:6a:28:9f:51:62:63:d9:7d:1a: + 81:a0:72:f7:9f:33:6b:3b:f4:dc:85:cd:2a:ee:83:a9:93:3d: + 75:53:91:fa:0b:1b:10:83:11:2c:03:4e:ac:bf:c3:e6:25:74: + 9f:14:13:4a:43:66:c2:d7:1c:6c:94:3e:a6:f3:a5:bd:01:2c: + 9f:20:29:2e:62:82:12:d8:8b:70:1b:88:2b:18:68:5a:45:80: + 46:2a:6a:d5:df:1f:d3:e8:57:39:0a:be:1a:d8:b0:3e:e5:b6: + c3:69:b7:5e:c0:7b:b3:a8:a6:78:ee:0a:3d:a0:74:40:fb:42: + 9f:f4:98:7f:47:cc:15:28:eb:b1:95:77:82:a8:65:9b:46:c3: + 4f:f9:f4:72:be:bd:24:28:5c:0d:b3:89:e4:13:71:c8:a7:54: + 1b:26:15:f3:c1:b2:a9:13:77:54:c2:b9:b0:c7:24:39:00:4c: + 1a:a7:9b:e7:ad:4a:3a:32:c2:81:0d:13:2d:27:ea:98:00:a9: + 0e:9e:38:3b:8f:80:34:17:17:3d:49:7e:f4:a5:19:05:28:08: + 7d:de:d3:1f +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAOv0BS09D8bzMA0GCSqGSIb3DQEBBQUAMIGAMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKY3liZXJzcGFjZTEnMCUGA1UECgweTEVBUCBFbmNy +eXB0aW9uIEFjY2VzcyBQcm9qZWN0MRYwFAYDVQQDDA10ZXN0cy1sZWFwLnNlMRsw +GQYJKoZIhvcNAQkBFgxpbmZvQGxlYXAuc2UwHhcNMTIwODMxMTYzMDE3WhcNMTMw +ODMxMTYzMDE3WjCBijELMAkGA1UEBhMCVVMxEzARBgNVBAgMCmN5YmVyc3BhY2Ux +DDAKBgNVBAcMA25ldDEnMCUGA1UECgweTEVBUCBFbmNyeXB0aW9uIEFjY2VzcyBQ +cm9qZWN0MRIwEAYDVQQDDAlsb2NhbGhvc3QxGzAZBgkqhkiG9w0BCQEWDGluZm9A +bGVhcC5zZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALzxxAXOS9Wb +mvrBpQyJFX4FabakYjg61hRKNqo8MXBULr99BRmtewyppn1GvoNiy+q5SGx9eKAQ +C62KdHq4/zKFZDaQ3DjdkG4HgnCuX04f9EaY85i0+ghlv9bsqbp+qPBAotAay+b8 +lcVUY5JbuAo2zCbTK60W/0lT9GV8ZCea9RJ1EaUMWuoe5DHzpivbDkpdqkc68F4q +1W90tvi8mnPQ+oq+qGlHmwdF2bXNHJvFQZplzJmgvb+16J9mX2nJbchoUGh0ro4S +fpwkT9wFYbeKbSqVQ9k//tjJp65jzTDVlYQYLRK1Lab+N910uPilWRiPyveuYw2d +ZlF9nEBIm6ECAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3Bl +blNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFLJQtMY4j7rEO2lM +a0V8zwhINgLgMB8GA1UdIwQYMBaAFJ6SRL+BZ5aim35u5qa7nSna5zgKMA0GCSqG +SIb3DQEBBQUAA4IBAQCqq9Qn48tCBVX9JLPlVX37zmz/x5bwfTChU0oE66QkXpbu +Ze/lqghHnaqVKrtqKJ9RYmPZfRqBoHL3nzNrO/Tchc0q7oOpkz11U5H6CxsQgxEs +A06sv8PmJXSfFBNKQ2bC1xxslD6m86W9ASyfICkuYoIS2ItwG4grGGhaRYBGKmrV +3x/T6Fc5Cr4a2LA+5bbDabdewHuzqKZ47go9oHRA+0Kf9Jh/R8wVKOuxlXeCqGWb +RsNP+fRyvr0kKFwNs4nkE3HIp1QbJhXzwbKpE3dUwrmwxyQ5AEwap5vnrUo6MsKB +DRMtJ+qYAKkOnjg7j4A0Fxc9SX70pRkFKAh93tMf +-----END CERTIFICATE----- diff --git a/src/leap/common/testing/leaptestskey.pem b/src/leap/common/testing/leaptestskey.pem new file mode 100644 index 0000000..fe6291a --- /dev/null +++ b/src/leap/common/testing/leaptestskey.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAvPHEBc5L1Zua+sGlDIkVfgVptqRiODrWFEo2qjwxcFQuv30F +Ga17DKmmfUa+g2LL6rlIbH14oBALrYp0erj/MoVkNpDcON2QbgeCcK5fTh/0Rpjz +mLT6CGW/1uypun6o8ECi0BrL5vyVxVRjklu4CjbMJtMrrRb/SVP0ZXxkJ5r1EnUR +pQxa6h7kMfOmK9sOSl2qRzrwXirVb3S2+Lyac9D6ir6oaUebB0XZtc0cm8VBmmXM +maC9v7Xon2ZfacltyGhQaHSujhJ+nCRP3AVht4ptKpVD2T/+2MmnrmPNMNWVhBgt +ErUtpv433XS4+KVZGI/K965jDZ1mUX2cQEiboQIDAQABAoIBAQCh/+yhSbrtoCgm +PegEsnix/3QfPBxWt+Obq/HozglZlWQrnMbFuF+bgM4V9ZUdU5UhYNF+66mEG53X +orGyE3IDYCmHO3cGbroKDPhDIs7mTjGEYlniIbGLh6oPXgU8uKKis9ik84TGPOUx +NuTUtT07zLYHx+FX3DLwLUKLzTaWWSRgA7nxNwCY8aPqDxCkXEyZHvSlm9KYZnhe +nVevycoHR+chxL6X/ebbBt2FKR7tl4328mlDXvMXr0vahPH94CuXEvfTj+f6ZxZF +OctdikyRfd8O3ebrUw0XjafPYyTsDMH0/rQovEBVlecEHqh6Z9dBFlogRq5DSun9 +jem4bBXRAoGBAPGPi4g21pTQPqTFxpqea8TsPqIfo3csfMDPdzT246MxzALHqCfG +yZi4g2JYJrReSWHulZDORO5skSKNEb5VTA/3xFhKLt8CULZOakKBDLkzRXlnDFXg +Jsu9vtjDWjQcJsdsRx1tc5V6s+hmel70aaUu/maUlEYZnyIXaTe+1SB1AoGBAMg9 +EMEO5YN52pOI5qPH8j7uyVKtZWKRiR6jb5KA5TxWqZalSdPV6YwDqV/e+HjWrZNw +kSEFONY0seKpIHwXchx91aym7rDHUgOoBQfCWufRMYvRXLhfOTBu4X+U52++i8wt +FvKgh6eSmc7VayAaDfHp7yfrIfS03IiN0T35mGj9AoGAPCoXg7a83VW8tId5/trE +VsjMlM6yhSU0cUV7GFsBuYzWlj6qODX/0iTqvFzeTwBI4LZu1CE78/Jgd62RJMnT +5wo8Ag1//RVziuSe/K9tvtbxT9qFrQHmR8qbtRt65Q257uOeFstDBZEJLDIR+oJ/ +qZ+5x0zsXUVWaERSdYr3RF0CgYEApKDgN3oB5Ti4Jnh1984aMver+heptYKmU9RX +lQH4dsVhpQO8UTgcTgtso+/0JZWLHB9+ksFyW1rzrcETfjLglOA4XzzYHeuiWHM5 +v4lhqBpsO+Ij80oHAPUI3RYVud/VnEauCUlGftWfM1hwPPJu6KhHAnDleAWDE5pV +oDinwBkCgYEAnn/OceaqA2fNYp1IRegbFzpewjUlHLq3bXiCIVhO7W/HqsdfUxjE +VVdjEno/pAG7ZCO5j8u+rLkG2ZIVY3qsUENUiXz52Q08qEltgM8nfirK7vIQkfd9 +YISRE3QHYJd+ArY4v+7rNeF1O5eIEyzPAbvG5raeZFcZ6POxy66uWKo= +-----END RSA PRIVATE KEY----- diff --git a/src/leap/common/testing/test_basetest.py b/src/leap/common/testing/test_basetest.py new file mode 100644 index 0000000..3674185 --- /dev/null +++ b/src/leap/common/testing/test_basetest.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +# leap.common.testing.test_basetest +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +Unittests for base test +...becase it's oh so meta""" +try: + import unittest2 as unittest +except ImportError: + import unittest + +import os +import StringIO + +from leap.testing.basetest import BaseLeapTest + +# global for tempdir checking +_tempdir = None + + +class _TestCaseRunner(object): + def run_testcase(self, testcase=None): + if not testcase: + return None + loader = unittest.TestLoader() + suite = loader.loadTestsFromTestCase(testcase) + + # Create runner, and run testcase + io = StringIO.StringIO() + runner = unittest.TextTestRunner(stream=io) + results = runner.run(suite) + return results + + +class TestAbstractBaseLeapTest(unittest.TestCase, _TestCaseRunner): + + def test_abstract_base_class(self): + class _BaseTest(BaseLeapTest): + def test_dummy_method(self): + pass + + def test_tautology(self): + assert True + + results = self.run_testcase(_BaseTest) + + # should be 2 errors: NotImplemented + # raised for setUp/tearDown + self.assertEquals(results.testsRun, 2) + self.assertEquals(len(results.failures), 0) + self.assertEquals(len(results.errors), 2) + + +class TestInitBaseLeapTest(BaseLeapTest): + + def setUp(self): + pass + + def tearDown(self): + pass + + def test_path_is_changed(self): + os_path = os.environ['PATH'] + self.assertTrue(os_path.startswith(self.tempdir)) + + def test_old_path_is_saved(self): + self.assertTrue(len(self.old_path) > 1) + + +class TestCleanedBaseLeapTest(unittest.TestCase, _TestCaseRunner): + + def test_tempdir_is_cleaned_after_tests(self): + class _BaseTest(BaseLeapTest): + def setUp(self): + global _tempdir + _tempdir = self.tempdir + + def tearDown(self): + pass + + def test_tempdir_created(self): + self.assertTrue(os.path.isdir(self.tempdir)) + + def test_tempdir_created_on_setupclass(self): + self.assertEqual(_tempdir, self.tempdir) + + results = self.run_testcase(_BaseTest) + self.assertEquals(results.testsRun, 2) + self.assertEquals(len(results.failures), 0) + self.assertEquals(len(results.errors), 0) + + # did we cleaned the tempdir? + self.assertFalse(os.path.isdir(_tempdir)) + +if __name__ == "__main__": + unittest.main() |