Minor changes for testing on non-Linux platforms #1838

Merged
g1itch merged 4 commits from windows-test into v0.6 2021-09-05 14:22:43 +02:00
8 changed files with 86 additions and 71 deletions

View File

@ -18,5 +18,5 @@ install:
- export PYTHONWARNINGS=all - export PYTHONWARNINGS=all
script: script:
- python checkdeps.py - python checkdeps.py
- xvfb-run src/bitmessagemain.py -t - python src/bitmessagemain.py -t
- python -bm tests - python -bm tests

View File

@ -1,6 +1,7 @@
coverage coverage
python_prctl
psutil psutil
pycrypto pycrypto
six
PyQt5;python_version>="3.7" PyQt5;python_version>="3.7"
python_prctl;platform_system=="Linux"
six
xvfbwrapper;platform_system=="Linux"

View File

@ -21,16 +21,13 @@ app_dir = pathmagic.setup()
import depends import depends
depends.check_dependencies() depends.check_dependencies()
import ctypes
import getopt import getopt
import multiprocessing import multiprocessing
# Used to capture a Ctrl-C keypress so that Bitmessage can shutdown gracefully. # Used to capture a Ctrl-C keypress so that Bitmessage can shutdown gracefully.
import signal import signal
import socket
import threading import threading
import time import time
import traceback import traceback
from struct import pack
import defaults import defaults
import shared import shared
@ -39,7 +36,7 @@ import state
from bmconfigparser import BMConfigParser from bmconfigparser import BMConfigParser
from debug import logger # this should go before any threads from debug import logger # this should go before any threads
from helper_startup import ( from helper_startup import (
adjustHalfOpenConnectionsLimit, start_proxyconfig) adjustHalfOpenConnectionsLimit, fixSocket, start_proxyconfig)
from inventory import Inventory from inventory import Inventory
# Network objects and threads # Network objects and threads
from network import ( from network import (
@ -54,67 +51,6 @@ from threads import (
addressGenerator, objectProcessor, singleCleaner, singleWorker, sqlThread) addressGenerator, objectProcessor, singleCleaner, singleWorker, sqlThread)
def _fixSocket():
if sys.platform.startswith('linux'):
socket.SO_BINDTODEVICE = 25
if not sys.platform.startswith('win'):
return
# Python 2 on Windows doesn't define a wrapper for
# socket.inet_ntop but we can make one ourselves using ctypes
if not hasattr(socket, 'inet_ntop'):
addressToString = ctypes.windll.ws2_32.WSAAddressToStringA
def inet_ntop(family, host):
"""Converting an IP address in packed
binary format to string format"""
if family == socket.AF_INET:
if len(host) != 4:
raise ValueError("invalid IPv4 host")
host = pack("hH4s8s", socket.AF_INET, 0, host, "\0" * 8)
elif family == socket.AF_INET6:
if len(host) != 16:
raise ValueError("invalid IPv6 host")
host = pack("hHL16sL", socket.AF_INET6, 0, 0, host, 0)
else:
raise ValueError("invalid address family")
buf = "\0" * 64
lengthBuf = pack("I", len(buf))
addressToString(host, len(host), None, buf, lengthBuf)
return buf[0:buf.index("\0")]
socket.inet_ntop = inet_ntop
# Same for inet_pton
if not hasattr(socket, 'inet_pton'):
stringToAddress = ctypes.windll.ws2_32.WSAStringToAddressA
def inet_pton(family, host):
"""Converting an IP address in string format
to a packed binary format"""
buf = "\0" * 28
lengthBuf = pack("I", len(buf))
if stringToAddress(str(host),
int(family),
None,
buf,
lengthBuf) != 0:
raise socket.error("illegal IP address passed to inet_pton")
if family == socket.AF_INET:
return buf[4:8]
elif family == socket.AF_INET6:
return buf[8:24]
else:
raise ValueError("invalid address family")
socket.inet_pton = inet_pton
# These sockopts are needed on for IPv6 support
if not hasattr(socket, 'IPPROTO_IPV6'):
socket.IPPROTO_IPV6 = 41
if not hasattr(socket, 'IPV6_V6ONLY'):
socket.IPV6_V6ONLY = 27
def signal_handler(signum, frame): def signal_handler(signum, frame):
"""Single handler for any signal sent to pybitmessage""" """Single handler for any signal sent to pybitmessage"""
process = multiprocessing.current_process() process = multiprocessing.current_process()
@ -151,7 +87,7 @@ class Main(object):
def start(self): def start(self):
"""Start main application""" """Start main application"""
# pylint: disable=too-many-statements,too-many-branches,too-many-locals # pylint: disable=too-many-statements,too-many-branches,too-many-locals
_fixSocket() fixSocket()
adjustHalfOpenConnectionsLimit() adjustHalfOpenConnectionsLimit()
config = BMConfigParser() config = BMConfigParser()

View File

@ -3,12 +3,15 @@ Startup operations.
""" """
# pylint: disable=too-many-branches,too-many-statements # pylint: disable=too-many-branches,too-many-statements
import ctypes
import logging import logging
import os import os
import platform import platform
import socket
import sys import sys
import time import time
from distutils.version import StrictVersion from distutils.version import StrictVersion
from struct import pack
try: try:
import defaults import defaults
@ -304,6 +307,68 @@ def adjustHalfOpenConnectionsLimit():
state.maximumNumberOfHalfOpenConnections = 9 if is_limited else 64 state.maximumNumberOfHalfOpenConnections = 9 if is_limited else 64
def fixSocket():
"""Add missing socket options and methods mainly on Windows"""
if sys.platform.startswith('linux'):
socket.SO_BINDTODEVICE = 25
if not sys.platform.startswith('win'):
return
# Python 2 on Windows doesn't define a wrapper for
# socket.inet_ntop but we can make one ourselves using ctypes
if not hasattr(socket, 'inet_ntop'):
addressToString = ctypes.windll.ws2_32.WSAAddressToStringA
def inet_ntop(family, host):
"""Converting an IP address in packed
binary format to string format"""
if family == socket.AF_INET:
if len(host) != 4:
raise ValueError("invalid IPv4 host")
host = pack("hH4s8s", socket.AF_INET, 0, host, "\0" * 8)
elif family == socket.AF_INET6:
if len(host) != 16:
raise ValueError("invalid IPv6 host")
host = pack("hHL16sL", socket.AF_INET6, 0, 0, host, 0)
else:
raise ValueError("invalid address family")
buf = "\0" * 64
lengthBuf = pack("I", len(buf))
addressToString(host, len(host), None, buf, lengthBuf)
return buf[0:buf.index("\0")]
socket.inet_ntop = inet_ntop
# Same for inet_pton
if not hasattr(socket, 'inet_pton'):
stringToAddress = ctypes.windll.ws2_32.WSAStringToAddressA
def inet_pton(family, host):
"""Converting an IP address in string format
to a packed binary format"""
buf = "\0" * 28
lengthBuf = pack("I", len(buf))
if stringToAddress(str(host),
int(family),
None,
buf,
lengthBuf) != 0:
raise socket.error("illegal IP address passed to inet_pton")
if family == socket.AF_INET:
return buf[4:8]
elif family == socket.AF_INET6:
return buf[8:24]
else:
raise ValueError("invalid address family")
socket.inet_pton = inet_pton
# These sockopts are needed on for IPv6 support
if not hasattr(socket, 'IPPROTO_IPV6'):
socket.IPPROTO_IPV6 = 41
if not hasattr(socket, 'IPV6_V6ONLY'):
socket.IPV6_V6ONLY = 27
def start_proxyconfig(): def start_proxyconfig():
"""Check socksproxytype and start any proxy configuration plugin""" """Check socksproxytype and start any proxy configuration plugin"""
if not get_plugin: if not get_plugin:

View File

@ -3,6 +3,7 @@ Tests for core and those that do not work outside
(because of import error for example) (because of import error for example)
""" """
import atexit
import os import os
import pickle # nosec import pickle # nosec
import Queue import Queue
@ -416,8 +417,9 @@ def run():
suite = loader.loadTestsFromTestCase(TestCore) suite = loader.loadTestsFromTestCase(TestCore)
try: try:
import bitmessageqt.tests import bitmessageqt.tests
from xvfbwrapper import Xvfb
except ImportError: except ImportError:
pass Xvfb = None
else: else:
qt_tests = loader.loadTestsFromModule(bitmessageqt.tests) qt_tests = loader.loadTestsFromModule(bitmessageqt.tests)
suite.addTests(qt_tests) suite.addTests(qt_tests)
@ -428,4 +430,8 @@ def run():
sys.excepthook = keep_exc sys.excepthook = keep_exc
if Xvfb:
vdisplay = Xvfb(width=1024, height=768)
vdisplay.start()
atexit.register(vdisplay.stop)
return unittest.TextTestRunner(verbosity=2).run(suite) return unittest.TextTestRunner(verbosity=2).run(suite)

View File

@ -29,7 +29,7 @@ format=%(asctime)s {1} %(message)s
class=FileHandler class=FileHandler
level=NOTSET level=NOTSET
formatter=default formatter=default
args=('{0}', 'w') args=({0!r}, 'w')
[logger_root] [logger_root]
level=DEBUG level=DEBUG

View File

@ -192,6 +192,7 @@ class TestProcessShutdown(TestProcessProto):
class TestProcess(TestProcessProto): class TestProcess(TestProcessProto):
"""A test case for pybitmessage process""" """A test case for pybitmessage process"""
@unittest.skipIf(sys.platform[:5] != 'linux', 'probably needs prctl')
def test_process_name(self): def test_process_name(self):
"""Check PyBitmessage process name""" """Check PyBitmessage process name"""
self.assertEqual(self.process.name(), 'PyBitmessage') self.assertEqual(self.process.name(), 'PyBitmessage')

View File

@ -6,11 +6,17 @@ import sys
import unittest import unittest
from pybitmessage import protocol, state from pybitmessage import protocol, state
from pybitmessage.helper_startup import fixSocket
class TestProtocol(unittest.TestCase): class TestProtocol(unittest.TestCase):
"""Main protocol test case""" """Main protocol test case"""
@classmethod
def setUpClass(cls):
"""Execute fixSocket() before start. Only for Windows?"""
fixSocket()
def test_checkIPv4Address(self): def test_checkIPv4Address(self):
"""Check the results of protocol.checkIPv4Address()""" """Check the results of protocol.checkIPv4Address()"""
token = 'HELLO' token = 'HELLO'