diff --git a/.travis.yml b/.travis.yml index 274d14c184..a1a314d91f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,9 @@ language: python +cache: pip +dist: bionic python: - - "2.7" + - "2.7_with_system_site_packages" + - "3.7" addons: apt: packages: @@ -11,9 +14,9 @@ addons: - xvfb install: - pip install -r requirements.txt - - ln -s src pybitmessage # tests environment - python setup.py install + - export PYTHONWARNINGS=all script: - python checkdeps.py - xvfb-run src/bitmessagemain.py -t - - python setup.py test + - python -bm tests diff --git a/checkdeps.py b/checkdeps.py index 619cd668e4..66ce1a8fe1 100755 --- a/checkdeps.py +++ b/checkdeps.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python """ Check dependencies and give recommendations about how to satisfy them diff --git a/requirements.txt b/requirements.txt index c55e5cf141..f9972a7ebb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +coverage python_prctl psutil pycrypto diff --git a/setup.py b/setup.py index 7a3bcf6a73..1c1de4544b 100644 --- a/setup.py +++ b/setup.py @@ -95,11 +95,14 @@ def run(self): ['desktop/icons/24x24/pybitmessage.png']) ] - if platform.dist()[0] in ('Debian', 'Ubuntu'): - data_files += [ - ("etc/apparmor.d/", - ['packages/apparmor/pybitmessage']) - ] + try: + if platform.dist()[0] in ('Debian', 'Ubuntu'): + data_files += [ + ("etc/apparmor.d/", + ['packages/apparmor/pybitmessage']) + ] + except AttributeError: + pass # FIXME: use distro for more recent python dist = setup( name='pybitmessage', @@ -116,6 +119,7 @@ def run(self): #keywords='', install_requires=installRequires, tests_require=requirements, + test_suite='tests.unittest_discover', extras_require=EXTRAS_REQUIRE, classifiers=[ "License :: OSI Approved :: MIT License" diff --git a/src/addresses.py b/src/addresses.py index fb86d40c9e..e21acd1f61 100644 --- a/src/addresses.py +++ b/src/addresses.py @@ -3,10 +3,12 @@ """ # pylint: disable=redefined-outer-name,inconsistent-return-statements import hashlib +import logging from binascii import hexlify, unhexlify from struct import pack, unpack -from debug import logger + +logger = logging.getLogger('default') ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" @@ -23,8 +25,7 @@ def encodeBase58(num, alphabet=ALPHABET): arr = [] base = len(alphabet) while num: - rem = num % base - num = num // base + num, rem = divmod(num, base) arr.append(alphabet[rem]) arr.reverse() return ''.join(arr) @@ -148,16 +149,16 @@ def encodeAddress(version, stream, ripe): 'Programming error in encodeAddress: The length of' ' a given ripe hash was not 20.' ) - if ripe[:2] == '\x00\x00': + if ripe[:2] == b'\x00\x00': ripe = ripe[2:] - elif ripe[:1] == '\x00': + elif ripe[:1] == b'\x00': ripe = ripe[1:] elif version == 4: if len(ripe) != 20: raise Exception( 'Programming error in encodeAddress: The length of' ' a given ripe hash was not 20.') - ripe = ripe.lstrip('\x00') + ripe = ripe.lstrip(b'\x00') storedBinaryData = encodeVarint(version) + encodeVarint(stream) + ripe @@ -191,8 +192,8 @@ def decodeAddress(address): status = 'invalidcharacters' return status, 0, 0, '' # after converting to hex, the string will be prepended - # with a 0x and appended with a L - hexdata = hex(integer)[2:-1] + # with a 0x and appended with a L in python2 + hexdata = hex(integer)[2:].rstrip('L') if len(hexdata) % 2 != 0: hexdata = '0' + hexdata @@ -242,13 +243,13 @@ def decodeAddress(address): data[bytesUsedByVersionNumber + bytesUsedByStreamNumber:-4] if len(embeddedRipeData) == 19: return status, addressVersionNumber, streamNumber, \ - '\x00' + embeddedRipeData + b'\x00' + embeddedRipeData elif len(embeddedRipeData) == 20: return status, addressVersionNumber, streamNumber, \ embeddedRipeData elif len(embeddedRipeData) == 18: return status, addressVersionNumber, streamNumber, \ - '\x00\x00' + embeddedRipeData + b'\x00\x00' + embeddedRipeData elif len(embeddedRipeData) < 18: return 'ripetooshort', 0, 0, '' elif len(embeddedRipeData) > 20: @@ -257,7 +258,7 @@ def decodeAddress(address): elif addressVersionNumber == 4: embeddedRipeData = \ data[bytesUsedByVersionNumber + bytesUsedByStreamNumber:-4] - if embeddedRipeData[0:1] == '\x00': + if embeddedRipeData[0:1] == b'\x00': # In order to enforce address non-malleability, encoded # RIPE data must have NULL bytes removed from the front return 'encodingproblem', 0, 0, '' @@ -265,7 +266,7 @@ def decodeAddress(address): return 'ripetoolong', 0, 0, '' elif len(embeddedRipeData) < 4: return 'ripetooshort', 0, 0, '' - x00string = '\x00' * (20 - len(embeddedRipeData)) + x00string = b'\x00' * (20 - len(embeddedRipeData)) return status, addressVersionNumber, streamNumber, \ x00string + embeddedRipeData diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index 1030ebb03e..7c2ed73352 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -983,7 +983,7 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F def loadInbox(): """Load the list of messages""" sys.stdout = sys.__stdout__ - print "Loading inbox messages..." + print("Loading inbox messages...") sys.stdout = printlog where = "toaddress || fromaddress || subject || message" @@ -1035,7 +1035,7 @@ def loadInbox(): def loadSent(): """Load the messages that sent""" sys.stdout = sys.__stdout__ - print "Loading sent messages..." + print("Loading sent messages...") sys.stdout = printlog where = "toaddress || fromaddress || subject || message" @@ -1121,7 +1121,7 @@ def loadSent(): def loadAddrBook(): """Load address book""" sys.stdout = sys.__stdout__ - print "Loading address book..." + print("Loading address book...") sys.stdout = printlog ret = sqlQuery("SELECT label, address FROM addressbook") @@ -1228,7 +1228,7 @@ def run(stdscr): def doShutdown(): """Shutting the app down""" sys.stdout = sys.__stdout__ - print "Shutting down..." + print("Shutting down...") sys.stdout = printlog shutdown.doCleanShutdown() sys.stdout = sys.__stdout__ diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 8d511ae1bc..b54805bb3d 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2.7 +#!/usr/bin/env python """ The PyBitmessage startup script """ @@ -12,10 +12,11 @@ import os import sys -app_dir = os.path.dirname(os.path.abspath(__file__)) -os.chdir(app_dir) -sys.path.insert(0, app_dir) - +try: + import pathmagic +except ImportError: + from pybitmessage import pathmagic +app_dir = pathmagic.setup() import depends depends.check_dependencies() @@ -377,11 +378,7 @@ def start(self): test_core_result = test_core.run() self.stop() test_core.cleanup() - sys.exit( - 'Core tests failed!' - if test_core_result.errors or test_core_result.failures - else 0 - ) + sys.exit(not test_core_result.wasSuccessful()) @staticmethod def daemonize(): diff --git a/src/depends.py b/src/depends.py index 03e297f1ee..75be30e090 100755 --- a/src/depends.py +++ b/src/depends.py @@ -421,8 +421,8 @@ def check_dependencies(verbose=False, optional=False): if sys.hexversion >= 0x3000000: logger.error( 'PyBitmessage does not support Python 3+. Python 2.7.4' - ' or greater is required.') - has_all_dependencies = False + ' or greater is required. Python 2.7.18 is recommended.') + sys.exit() check_functions = [check_ripemd160, check_sqlite, check_openssl] if optional: diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index 41757f3707..cbe0fa2522 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -749,7 +749,7 @@ def log(self, message): def log_info(self, message, log_type='info'): """Conditionally print a message""" if log_type not in self.ignore_log_types: - print '%s: %s' % (log_type, message) + print('%s: %s' % (log_type, message)) def handle_read_event(self): """Handle a read event""" diff --git a/src/network/http.py b/src/network/http.py index 8bba38ac7f..d7a938fab3 100644 --- a/src/network/http.py +++ b/src/network/http.py @@ -18,19 +18,19 @@ def __init__(self, host, path="/"): # pylint: disable=redefined-outer-name self.destination = (host, 80) self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.connect(self.destination) - print "connecting in background to %s:%i" % (self.destination[0], self.destination[1]) + print("connecting in background to %s:%i" % self.destination) def state_init(self): self.append_write_buf( "GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n" % ( self.path, self.destination[0])) - print "Sending %ib" % (len(self.write_buf)) + print("Sending %ib" % len(self.write_buf)) self.set_state("http_request_sent", 0) return False def state_http_request_sent(self): if self.read_buf: - print "Received %ib" % (len(self.read_buf)) + print("Received %ib" % len(self.read_buf)) self.read_buf = b"" if not self.connected: self.set_state("close", 0) @@ -62,13 +62,13 @@ def state_socks_handshake_done(self): for host in ("bootstrap8080.bitmessage.org", "bootstrap8444.bitmessage.org"): proxy = Socks5Resolver(host=host) while asyncore.socket_map: - print "loop %s, len %i" % (proxy.state, len(asyncore.socket_map)) + print("loop %s, len %i" % (proxy.state, len(asyncore.socket_map))) asyncore.loop(timeout=1, count=1) proxy.resolved() proxy = Socks4aResolver(host=host) while asyncore.socket_map: - print "loop %s, len %i" % (proxy.state, len(asyncore.socket_map)) + print("loop %s, len %i" % (proxy.state, len(asyncore.socket_map))) asyncore.loop(timeout=1, count=1) proxy.resolved() diff --git a/src/openclpow.py b/src/openclpow.py index a086c81f7c..b8acbd4b65 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -1,16 +1,24 @@ -#!/usr/bin/env python2.7 """ Module for Proof of Work using OpenCL """ +import logging import os from struct import pack import paths from bmconfigparser import BMConfigParser -from debug import logger from state import shutdown -libAvailable = True +try: + import numpy + import pyopencl as cl + libAvailable = True +except ImportError: + libAvailable = False + + +logger = logging.getLogger('default') + ctx = False queue = False program = False @@ -19,17 +27,10 @@ vendors = [] hash_dt = None -try: - import pyopencl as cl - import numpy -except ImportError: - libAvailable = False - def initCL(): """Initlialise OpenCL engine""" - # pylint: disable=global-statement - global ctx, queue, program, hash_dt, libAvailable + global ctx, queue, program, hash_dt # pylint: disable=global-statement if libAvailable is False: return del enabledGpus[:] diff --git a/src/pathmagic.py b/src/pathmagic.py new file mode 100644 index 0000000000..3f32c0c1ef --- /dev/null +++ b/src/pathmagic.py @@ -0,0 +1,10 @@ +import os +import sys + + +def setup(): + """Add path to this file to sys.path""" + app_dir = os.path.dirname(os.path.abspath(__file__)) + os.chdir(app_dir) + sys.path.insert(0, app_dir) + return app_dir diff --git a/src/pyelliptic/arithmetic.py b/src/pyelliptic/arithmetic.py index 83e634adf9..cb3049c033 100644 --- a/src/pyelliptic/arithmetic.py +++ b/src/pyelliptic/arithmetic.py @@ -16,7 +16,7 @@ def inv(a, n): lm, hm = 1, 0 low, high = a % n, n while low > 1: - r = high / low + r = high // low nm, new = hm - lm * r, high - low * r lm, low, hm, high = nm, new, lm, low return lm % n @@ -43,8 +43,8 @@ def encode(val, base, minlen=0): code_string = get_code_string(base) result = "" while val > 0: - result = code_string[val % base] + result - val /= base + val, i = divmod(val, base) + result = code_string[i] + result if len(result) < minlen: result = code_string[0] * (minlen - len(result)) + result return result @@ -101,10 +101,11 @@ def base10_multiply(a, n): return G if n == 1: return a - if (n % 2) == 0: - return base10_double(base10_multiply(a, n / 2)) - if (n % 2) == 1: - return base10_add(base10_double(base10_multiply(a, n / 2)), a) + n, m = divmod(n, 2) + if m == 0: + return base10_double(base10_multiply(a, n)) + if m == 1: + return base10_add(base10_double(base10_multiply(a, n)), a) return None diff --git a/src/pyelliptic/cipher.py b/src/pyelliptic/cipher.py index 4057e16957..af6c08ca81 100644 --- a/src/pyelliptic/cipher.py +++ b/src/pyelliptic/cipher.py @@ -1,12 +1,10 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- """ Symmetric Encryption """ # Copyright (C) 2011 Yann GUIBET # See LICENSE for details. -from openssl import OpenSSL +from .openssl import OpenSSL # pylint: disable=redefined-builtin diff --git a/src/pyelliptic/ecc.py b/src/pyelliptic/ecc.py index a7f5a6b7c4..388227c7d8 100644 --- a/src/pyelliptic/ecc.py +++ b/src/pyelliptic/ecc.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- """ Asymmetric cryptography using elliptic curves """ @@ -10,9 +8,9 @@ from hashlib import sha512 from struct import pack, unpack -from cipher import Cipher -from hash import equals, hmac_sha256 -from openssl import OpenSSL +from .cipher import Cipher +from .hash import equals, hmac_sha256 +from .openssl import OpenSSL class ECC(object): diff --git a/src/pyelliptic/eccblind.py b/src/pyelliptic/eccblind.py index a417451ecf..83bc7632d6 100644 --- a/src/pyelliptic/eccblind.py +++ b/src/pyelliptic/eccblind.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python """ ECC blind signature functionality based on "An Efficient Blind Signature Scheme @@ -151,7 +150,7 @@ def _ec_point_serialize(self, point): # padding manually bx = OpenSSL.malloc(0, OpenSSL.BN_num_bytes(x)) OpenSSL.BN_bn2bin(x, bx) - out = bx.raw.rjust(l_, chr(0)) + out = bx.raw.rjust(l_, b'\x00') return pack(EC, y_byte, out) finally: @@ -181,7 +180,7 @@ def _bn_serialize(self, bn): except AttributeError: o = OpenSSL.malloc(0, OpenSSL.BN_num_bytes(bn)) OpenSSL.BN_bn2bin(bn, o) - return o.raw.rjust(l_, chr(0)) + return o.raw.rjust(l_, b'\x00') def _bn_deserialize(self, data): """Make a BigNum out of string""" diff --git a/src/pyelliptic/hash.py b/src/pyelliptic/hash.py index f098d63190..70c9a6ce8b 100644 --- a/src/pyelliptic/hash.py +++ b/src/pyelliptic/hash.py @@ -4,7 +4,7 @@ # Copyright (C) 2011 Yann GUIBET # See LICENSE for details. -from openssl import OpenSSL +from .openssl import OpenSSL # For python3 diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index accaaa949c..abc6ac13f8 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -83,7 +83,7 @@ def __init__(self, library): """ self._lib = ctypes.CDLL(library) self._version, self._hexversion, self._cflags = get_version(self._lib) - self._libreSSL = self._version.startswith("LibreSSL") + self._libreSSL = self._version.startswith(b"LibreSSL") self.pointer = ctypes.pointer self.c_int = ctypes.c_int diff --git a/src/tests/apinotify_handler.py b/src/tests/apinotify_handler.py index 4574d46ae8..d3993f4db3 100755 --- a/src/tests/apinotify_handler.py +++ b/src/tests/apinotify_handler.py @@ -7,7 +7,7 @@ import sys import tempfile -from test_process import put_signal_file +from common import put_signal_file if __name__ == '__main__': diff --git a/src/tests/common.py b/src/tests/common.py index 2f130e25c6..e87765a49e 100644 --- a/src/tests/common.py +++ b/src/tests/common.py @@ -1,4 +1,7 @@ import os +import sys +import time +import unittest _files = ( @@ -17,3 +20,15 @@ def cleanup(home=None, files=_files): os.remove(os.path.join(home, pfile)) except OSError: pass + + +def skip_python3(): + """Raise unittest.SkipTest() if detected python3""" + if sys.hexversion >= 0x3000000: + raise unittest.SkipTest('Module is not ported to python3') + + +def put_signal_file(path, filename): + """Creates file, presence of which is a signal about some event.""" + with open(os.path.join(path, filename), 'wb') as outfile: + outfile.write(b'%i' % time.time()) diff --git a/src/tests/test_api.py b/src/tests/test_api.py index e3756f5478..43c97233cd 100644 --- a/src/tests/test_api.py +++ b/src/tests/test_api.py @@ -5,9 +5,13 @@ import base64 import json import time -import xmlrpclib # nosec -from test_process import TestProcessProto, TestProcessShutdown +try: # nosec + from xmlrpclib import ServerProxy, ProtocolError +except ImportError: + from xmlrpc.client import ServerProxy, ProtocolError + +from .test_process import TestProcessProto, TestProcessShutdown class TestAPIProto(TestProcessProto): @@ -19,7 +23,7 @@ def setUpClass(cls): """Setup XMLRPC proxy for pybitmessage API""" super(TestAPIProto, cls).setUpClass() cls.addresses = [] - cls.api = xmlrpclib.ServerProxy( + cls.api = ServerProxy( "http://username:password@127.0.0.1:8442/") for _ in range(5): if cls._get_readline('.api_started'): @@ -65,8 +69,8 @@ def _add_random_address(self, label): def test_user_password(self): """Trying to connect with wrong username/password""" - api_wrong = xmlrpclib.ServerProxy("http://test:wrong@127.0.0.1:8442/") - with self.assertRaises(xmlrpclib.ProtocolError): + api_wrong = ServerProxy("http://test:wrong@127.0.0.1:8442/") + with self.assertRaises(ProtocolError): api_wrong.clientStatus() def test_connection(self): diff --git a/src/tests/test_blindsig.py b/src/tests/test_blindsig.py index cae161913c..4994d87c14 100644 --- a/src/tests/test_blindsig.py +++ b/src/tests/test_blindsig.py @@ -5,9 +5,7 @@ import unittest from hashlib import sha256 -from pybitmessage.pyelliptic.eccblind import ECCBlind -from pybitmessage.pyelliptic.eccblindchain import ECCBlindChain -from pybitmessage.pyelliptic.openssl import OpenSSL +from pybitmessage.pyelliptic import ECCBlind, ECCBlindChain, OpenSSL # pylint: disable=protected-access @@ -36,12 +34,12 @@ def test_blind_sig(self): # (3) Signature Generation signature_blinded = signer_obj.blind_sign(msg_blinded) - assert isinstance(signature_blinded, str) + assert isinstance(signature_blinded, bytes) self.assertEqual(len(signature_blinded), 32) # (4) Extraction signature = requester_obj.unblind(signature_blinded) - assert isinstance(signature, str) + assert isinstance(signature, bytes) self.assertEqual(len(signature), 65) self.assertNotEqual(signature, signature_blinded) @@ -163,7 +161,7 @@ def test_blind_sig_chain(self): # pylint: disable=too-many-locals output.extend(pubkey) output.extend(signature) signer_obj = child_obj - verifychain = ECCBlindChain(ca=ca.pubkey(), chain=str(output)) + verifychain = ECCBlindChain(ca=ca.pubkey(), chain=bytes(output)) self.assertTrue(verifychain.verify(msg=msg, value=1)) def test_blind_sig_chain_wrong_ca(self): # pylint: disable=too-many-locals diff --git a/src/tests/test_config.py b/src/tests/test_config.py index fcf8c49847..a3b90a4cfe 100644 --- a/src/tests/test_config.py +++ b/src/tests/test_config.py @@ -6,8 +6,8 @@ import unittest import tempfile +from .test_process import TestProcessProto from pybitmessage.bmconfigparser import BMConfigParser -from test_process import TestProcessProto class TestConfig(unittest.TestCase): diff --git a/src/tests/test_crypto.py b/src/tests/test_crypto.py index b53105cb2d..b94f626eff 100644 --- a/src/tests/test_crypto.py +++ b/src/tests/test_crypto.py @@ -6,8 +6,10 @@ import unittest from abc import ABCMeta, abstractmethod from binascii import hexlify, unhexlify + from pybitmessage.pyelliptic import arithmetic + try: from Crypto.Hash import RIPEMD except ImportError: @@ -21,14 +23,21 @@ sample_pubencryptionkey = unhexlify( '044597d59177fc1d89555d38915f581b5ff2286b39d022ca0283d2bdd5c36be5d3c' 'e7b9b97792327851a562752e4b79475d1f51f5a71352482b241227f45ed36a9') -sample_privatesigningkey = \ +sample_privsigningkey = \ '93d0b61371a54b53df143b954035d612f8efa8a3ed1cf842c2186bfd8f876665' -sample_privateencryptionkey = \ +sample_privencryptionkey = \ '4b0b73a54e19b059dc274ab69df095fe699f43b17397bca26fdf40f4d7400a3a' -sample_ripe = '003cd097eb7f35c87b5dc8b4538c22cb55312a9f' +sample_ripe = b'003cd097eb7f35c87b5dc8b4538c22cb55312a9f' # stream: 1, version: 2 sample_address = 'BM-onkVu1KKL2UaUss5Upg9vXmqd3esTmV79' +sample_factor = 66858749573256452658262553961707680376751171096153613379801854825275240965733 +# G * sample_factor +sample_point = ( + 33567437183004486938355437500683826356288335339807546987348409590129959362313, + 94730058721143827257669456336351159718085716196507891067256111928318063085006 +) + _sha = hashlib.new('sha512') _sha.update(sample_pubsigningkey + sample_pubencryptionkey) @@ -69,14 +78,20 @@ def _hashdigest(data): class TestAddresses(unittest.TestCase): """Test addresses manipulations""" + def test_base10_multiply(self): + """Test arithmetic.base10_multiply""" + self.assertEqual( + sample_point, + arithmetic.base10_multiply(arithmetic.G, sample_factor)) + def test_privtopub(self): """Generate public keys and check the result""" self.assertEqual( - arithmetic.privtopub(sample_privatesigningkey), + arithmetic.privtopub(sample_privsigningkey).encode(), hexlify(sample_pubsigningkey) ) self.assertEqual( - arithmetic.privtopub(sample_privateencryptionkey), + arithmetic.privtopub(sample_privencryptionkey).encode(), hexlify(sample_pubencryptionkey) ) diff --git a/src/tests/test_logger.py b/src/tests/test_logger.py index a24667fdf3..da0f9341ec 100644 --- a/src/tests/test_logger.py +++ b/src/tests/test_logger.py @@ -5,7 +5,7 @@ import os import tempfile -from test_process import TestProcessProto +from .test_process import TestProcessProto class TestLogger(TestProcessProto): diff --git a/src/tests/test_networkgroup.py b/src/tests/test_networkgroup.py index 76cfb033f8..791634024b 100644 --- a/src/tests/test_networkgroup.py +++ b/src/tests/test_networkgroup.py @@ -3,6 +3,10 @@ """ import unittest +from .common import skip_python3 + +skip_python3() + class TestNetworkGroup(unittest.TestCase): """ diff --git a/src/tests/test_openclpow.py b/src/tests/test_openclpow.py index 63551ee2e8..6cfb5bd218 100644 --- a/src/tests/test_openclpow.py +++ b/src/tests/test_openclpow.py @@ -3,9 +3,12 @@ """ import hashlib import unittest - from struct import pack, unpack +from .common import skip_python3 + +skip_python3() # noqa:E402 + from pybitmessage import openclpow diff --git a/src/tests/test_openssl.py b/src/tests/test_openssl.py index e947fff3fb..c62bb8b33d 100644 --- a/src/tests/test_openssl.py +++ b/src/tests/test_openssl.py @@ -49,6 +49,6 @@ def test_padding(self): c = OpenSSL.malloc(0, OpenSSL.BN_num_bytes(a)) OpenSSL.BN_bn2binpad(a, b, OpenSSL.BN_num_bytes(n)) OpenSSL.BN_bn2bin(a, c) - if b.raw != c.raw.rjust(OpenSSL.BN_num_bytes(n), chr(0)): + if b.raw != c.raw.rjust(OpenSSL.BN_num_bytes(n), b'\x00'): bad += 1 self.assertEqual(bad, 0) diff --git a/src/tests/test_process.py b/src/tests/test_process.py index 3355ceaf5a..d976aa1875 100644 --- a/src/tests/test_process.py +++ b/src/tests/test_process.py @@ -12,13 +12,10 @@ import psutil -from common import cleanup +from .common import cleanup, put_signal_file, skip_python3 -def put_signal_file(path, filename): - """Creates file, presence of which is a signal about some event.""" - with open(os.path.join(path, filename), 'wb') as outfile: - outfile.write(str(time.time())) +skip_python3() class TestProcessProto(unittest.TestCase): @@ -198,6 +195,7 @@ def test_process_name(self): """Check PyBitmessage process name""" self.assertEqual(self.process.name(), 'PyBitmessage') + @unittest.skipIf(psutil.version_info < (4, 0), 'psutil is too old') def test_home(self): """Ensure BITMESSAGE_HOME is used by process""" self.assertEqual( @@ -207,7 +205,7 @@ def test_listening(self): """Check that pybitmessage listens on port 8444""" for c in self.process.connections(): if c.status == 'LISTEN': - self.assertEqual(c.laddr.port, 8444) + self.assertEqual(c.laddr[1], 8444) break def test_files(self): diff --git a/src/tests/test_protocol.py b/src/tests/test_protocol.py index 84d87a0f0f..a3c73a73f0 100644 --- a/src/tests/test_protocol.py +++ b/src/tests/test_protocol.py @@ -4,6 +4,10 @@ import unittest +from .common import skip_python3 + +skip_python3() + class TestProtocol(unittest.TestCase): """Main protocol test case""" diff --git a/src/tests/test_randomtrackingdict.py b/src/tests/test_randomtrackingdict.py index 40d2e01b61..bb66c0e2db 100644 --- a/src/tests/test_randomtrackingdict.py +++ b/src/tests/test_randomtrackingdict.py @@ -15,7 +15,7 @@ class TestRandomTrackingDict(unittest.TestCase): @staticmethod def randString(): """helper function for tests, generates a random string""" - retval = b'' + retval = '' for _ in range(32): retval += chr(random.randint(0, 255)) return retval diff --git a/stdeb.cfg b/stdeb.cfg index f542106937..2027d18c8d 100644 --- a/stdeb.cfg +++ b/stdeb.cfg @@ -6,3 +6,4 @@ Depends: openssl, python-setuptools Recommends: apparmor, python-msgpack, python-qt4, python-stem, tor Suggests: python-pyopencl, python-jsonrpclib, python-defusedxml, python-qrcode Suite: bionic +Setup-Env-Vars: DEB_BUILD_OPTIONS=nocheck diff --git a/tests.py b/tests.py new file mode 100644 index 0000000000..f0c82f772b --- /dev/null +++ b/tests.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Custom tests runner script for tox and python3""" +import random # noseq +import sys +import unittest + + +def unittest_discover(): + """Explicit test suite creation""" + if sys.hexversion >= 0x3000000: + from pybitmessage import pathmagic + pathmagic.setup() + loader = unittest.defaultTestLoader + # randomize the order of tests in test cases + loader.sortTestMethodsUsing = lambda a, b: random.randint(-1, 1) + # pybitmessage symlink may disappear on Windows + return loader.discover('src.tests') + + +if __name__ == "__main__": + result = unittest.TextTestRunner(verbosity=2).run(unittest_discover()) + sys.exit(not result.wasSuccessful()) diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000000..211afd477f --- /dev/null +++ b/tox.ini @@ -0,0 +1,34 @@ +[tox] +envlist = reset,py{27,37,38},stats +skip_missing_interpreters = true + +[testenv] +setenv = + BITMESSAGE_HOME = {envtmpdir} + PYTHONWARNINGS = all +deps = -rrequirements.txt +commands = + python checkdeps.py + coverage run -a src/bitmessagemain.py -t + coverage run -a -m tests + +[testenv:reset] +commands = coverage erase + +[testenv:stats] +commands = + coverage report + coverage xml + +[coverage:run] +source = src +omit = + */lib* + tests.py + */tests/* + src/version.py + */__init__.py + src/fallback/umsgpack/* + +[coverage:report] +ignore_errors = true