diff --git a/Makefile b/Makefile index 4b280f5..cd89ea8 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ check:: install:: ${PIP_EXE_MSYS} --python ${PYTHON_EXE_MSYS} install \ + --no-deps \ --target ${PREFIX}/lib/python${PYTHON_MINOR}/site-packages/ \ --upgrade . @@ -30,16 +31,20 @@ test:: test_direct:: cp -p ${HOME}/.config/tox/DHTnodes.json /tmp/toxygen_nodes.json PYTHONPATH=$${PWD}/src \ + TOR_CONTROLLER_PASSWORD=${PASS} \ sudo -u bin $(PYTHON_EXE_MSYS) src/toxygen_wrapper/tests/tests_wrapper.py \ + --norequest=True \ --socket_timeout=10.0 \ --test_timeout=${iTEST_TIMEOUT} \ --nodes_json=/tmp/toxygen_nodes.json \ --udp_enabled=True \ - --trace_enabled=False --loglevel=10 + --trace_enabled=False --loglevel=10 test_proxy:: PYTHONPATH=$${PWD}/src \ + TOR_CONTROLLER_PASSWORD=${PASS} \ ${PYTHON_EXE_MSYS} src/toxygen_wrapper/tests/tests_wrapper.py \ + --norequest=True \ --socket_timeout=15.0 \ --test_timeout=${iTEST_TIMEOUT} \ --proxy_host=127.0.0.1 \ diff --git a/src/toxygen_wrapper/tests/support_http.py b/src/toxygen_wrapper/tests/support_http.py index f3bc975..6dc7ffd 100644 --- a/src/toxygen_wrapper/tests/support_http.py +++ b/src/toxygen_wrapper/tests/support_http.py @@ -8,7 +8,7 @@ import urllib import traceback global LOG -LOG = logging.getLogger('app.'+'ts') +LOG = logging.getLogger('TestS') try: import pycurl diff --git a/src/toxygen_wrapper/tests/support_onions.py b/src/toxygen_wrapper/tests/support_onions.py index 324c889..4c2d6a0 100644 --- a/src/toxygen_wrapper/tests/support_onions.py +++ b/src/toxygen_wrapper/tests/support_onions.py @@ -1,4 +1,7 @@ # -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- +""" +Code to interact with a running to using the stem library. +""" import getpass import os @@ -9,31 +12,26 @@ import socket import sys import time from typing import Union, Callable, Union +import warnings -if False: - import cepa as stem - from cepa.connection import MissingPassword - from cepa.control import Controller - from cepa.util.tor_tools import is_valid_fingerprint -else: - import stem - from stem.connection import MissingPassword - from stem.control import Controller - from stem.util.tor_tools import is_valid_fingerprint +import stem +from stem.connection import MissingPassword +from stem.control import Controller +from stem.util.tor_tools import is_valid_fingerprint global LOG import logging -import warnings +from toxygen_wrapper.tests.support_http import bAreWeConnected warnings.filterwarnings('ignore') -LOG = logging.getLogger() +LOG = logging.getLogger('TestS') bHAVE_TORR = shutil.which('tor-resolve') - +oSTEM_CONTROLER = None yKNOWN_ONIONS = """ - facebookwkhpilnemxj7asaniu7vnjjbiltxjqhye3mhbshg7kx5tfyd # facebook - duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad # ddg - - zkaan2xfbuxia2wpf7ofnkbz6r5zdbbvxbunvp5g2iebopbfc4iqmbad # hks + - zkaan2xfbuxia2wpf7ofnkbz6r5zdbbvxbunvp5g2iebopbfc4iqmbad # keys.openpgp """ # grep -B 1 '
  • bool: - # FixMe: Linux only - sFile = f"/proc/{os.getpid()}/net/route" - if not os.path.isfile(sFile): return None - i = 0 - for elt in open(sFile, "r").readlines(): - if elt.startswith('Iface'): continue - if elt.startswith('lo'): continue - i += 1 - return i > 0 - -def sMapaddressResolv(target:str, iPort:int = 9051, log_level:int = 10) -> str: +def sMapaddressResolv(target:str, iPort:int = 9051, log_level:int = 10, password:[str,None] = None) -> str: if not stem: LOG.warn('please install the stem Python package') return '' try: - controller = oGetStemController(log_level=log_level) - + controller = oGetStemController(log_level=log_level, password=password) map_dict = {"0.0.0.0": target} map_ret = controller.map_address(map_dict) - return map_ret except Exception as e: LOG.exception(e) @@ -298,7 +297,7 @@ def sMapaddressResolv(target:str, iPort:int = 9051, log_level:int = 10) -> str: def vwait_for_controller(controller, wait_boot:int = 10) -> None: if bAreWeConnected() is False: - raise SystemExit("we are not connected") + raise RuntimeError("we are not connected") percent = i = 0 # You can call this while boostrapping while percent < 100 and i < wait_boot: @@ -314,17 +313,17 @@ def bin_to_hex(raw_id:int, length: Union[int, None] = None) -> str: res = ''.join('{:02x}'.format(raw_id[i]) for i in range(length)) return res.upper() -def lIntroductionPoints(controller=None, lOnions:list = [], itimeout:int = 120, log_level:int = 10): +def lIntroductionPoints(controller=None, lOnions:[list,None] = None, itimeout:int = 120, log_level:int = 10, password:[str,None] = None): """now working !!! stem 1.8.x timeout must be huge >120 'Provides the descriptor for a hidden service. The **address** is the '.onion' address of the hidden service ' What about Services? """ + if lOnions is None: lOnions = [] try: from cryptography.utils import int_from_bytes except ImportError: import cryptography.utils - # guessing - not in the current cryptography but stem expects it def int_from_bytes(**args): return int.to_bytes(*args) cryptography.utils.int_from_bytes = int_from_bytes @@ -341,7 +340,7 @@ def lIntroductionPoints(controller=None, lOnions:list = [], itimeout:int = 120, if type(lOnions) not in [set, tuple, list]: lOnions = list(lOnions) if controller is None: - controller = oGetStemController(log_level=log_level) + controller = oGetStemController(log_level=log_level, password=password) l = [] for elt in lOnions: LOG.info(f"controller.get_hidden_service_descriptor {elt}") @@ -529,7 +528,7 @@ def icheck_torrc(sFile:str, oArgs) -> int: print('VirtualAddrNetworkIPv4 172.16.0.0/12') return 0 -def lExitExcluder(oArgs, iPort:int = 9051, log_level:int = 10) -> list: +def lExitExcluder(oArgs, iPort:int = 9051, log_level:int = 10, password:[str,None] = None) -> list: """ https://raw.githubusercontent.com/nusenu/noContactInfo_Exit_Excluder/main/exclude_noContactInfo_Exits.py """ @@ -539,7 +538,7 @@ def lExitExcluder(oArgs, iPort:int = 9051, log_level:int = 10) -> list: LOG.debug('lExcludeExitNodes') try: - controller = oGetStemController(log_level=log_level) + controller = oGetStemController(log_level=log_level, password=password) # generator relays = controller.get_server_descriptors() except Exception as e: @@ -568,6 +567,6 @@ def lExitExcluder(oArgs, iPort:int = 9051, log_level:int = 10) -> list: return exit_excludelist if __name__ == '__main__': - target = 'duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad' + target = 'zkaan2xfbuxia2wpf7ofnkbz6r5zdbbvxbunvp5g2iebopbfc4iqmbad' controller = oGetStemController(log_level=10) lIntroductionPoints(controller, [target], itimeout=120) diff --git a/src/toxygen_wrapper/tests/support_testing.py b/src/toxygen_wrapper/tests/support_testing.py index bb20ed5..d88f1a8 100644 --- a/src/toxygen_wrapper/tests/support_testing.py +++ b/src/toxygen_wrapper/tests/support_testing.py @@ -49,7 +49,7 @@ from tox_wrapper.tests.support_onions import (is_valid_fingerprint, # LOG=util.log global LOG -LOG = logging.getLogger() +LOG = logging.getLogger('TestS') # callbacks can be called in any thread so were being careful def LOG_ERROR(l): print('EROR< '+l) @@ -148,10 +148,12 @@ def assert_main_thread() -> None: from qtpy.QtWidgets import QApplication # this "instance" method is very useful! - app_thread = QtWidgets.QApplication.instance().thread() - curr_thread = QtCore.QThread.currentThread() - if app_thread != curr_thread: - raise RuntimeError('attempt to call MainWindow.append_message from non-app thread') + app_instance = QtWidgets.QApplication.instance() + if app_instance: + app_thread = QtWidgets.QApplication.instance().thread() + curr_thread = QtCore.QThread.currentThread() + if app_thread != curr_thread: + raise RuntimeError('attempt to call MainWindow.append_message from non-app thread') @contextlib.contextmanager def ignoreStdout() -> None: diff --git a/src/toxygen_wrapper/tests/tests_wrapper.py b/src/toxygen_wrapper/tests/tests_wrapper.py index daeb23d..e3121cc 100644 --- a/src/toxygen_wrapper/tests/tests_wrapper.py +++ b/src/toxygen_wrapper/tests/tests_wrapper.py @@ -23,21 +23,24 @@ """Originaly from https://github.com/oxij/PyTox c-toxcore-02 branch which itself was forked from https://github.com/aitjcize/PyTox/ - Modified to work with toxygen_wrapper +Unlike almost all of the c-toxcore ctests, these are real tests that +take place over and Internet connection. -these tests create the alice and bob Toxes for each testcase. +These tests create the alice and bob Toxes for each testcase. We could do it once for the testsuite but we are testing a ctypes wrapper and what we think we've seen is errors in the wrapper can corrupt memory that shows as a SEGV but not nesessarily right-away: could be a little later. So for cleanliness and purity we remake the Toxes, which means we have to -wait in each test to get connected, which can be slow over tor: ~40 sec. is -not unusual, but less for directly connected. +wait in each test to get connected on tests that require connectivity, +which can be slow over tor: ~40 sec. is not unusual, but less for +directly connected. The other advantage of a fresh tox each time is +that the tests are more reproducible and comparable. -So typically this testsuite takes ~1000 sec. direct and 1300 sec. over Tor, -but Tor can have bad weeks so these Tor times could double or triple. +So typically this testsuite takes ~1000 sec. direct and 1500 sec. over Tor, +but Tor can have bad weeks so these Tor times could double or more. -We should consirder reusing a tox profile between testcases to cache the peers. +We should consider reusing a tox profile between testcases to cache the peers. """ @@ -85,17 +88,21 @@ except ImportError as e: import tox_wrapper import tox_wrapper.toxcore_enums_and_consts as enums from tox_wrapper.tox import Tox, UINT32_MAX, ToxError - -from tox_wrapper.toxcore_enums_and_consts import (TOX_ADDRESS_SIZE, TOX_CONNECTION, - TOX_FILE_CONTROL, - TOX_MESSAGE_TYPE, - TOX_SECRET_KEY_SIZE, - TOX_USER_STATUS) +from tox_wrapper.toxcore_enums_and_consts import (TOX_ADDRESS_SIZE, + TOX_CONNECTION, + TOX_FILE_CONTROL, + TOX_MESSAGE_TYPE, + TOX_SECRET_KEY_SIZE, + TOX_USER_STATUS) try: import support_testing as ts + import support_onions as so except ImportError: import tox_wrapper.tests.support_testing as ts + import tox_wrapper.tests.support_onions as so + +from wrapper_mixin import WrapperMixin try: from tests.toxygen_tests import test_sound_notification @@ -105,7 +112,6 @@ except ImportError: # from PyQt5 import QtCore import time - sleep = time.sleep global LOG @@ -248,7 +254,6 @@ def prepare(self): LOG_WARN(f"bobs_on_self_connection_status DISAGREE {status}") def alices_on_self_connection_status(iTox, connection_state: int, *args) -> None: - global oTOX_OARGS #FixMe connection_num status = connection_state self.alice.dht_connected = status @@ -289,8 +294,6 @@ def prepare(self): LOG.warning(f"doOnce not local and NOT CONNECTED") return [bob, alice] -from wrapper_mixin import WrapperMixin - class ToxSuite(unittest.TestCase, WrapperMixin): failureException = AssertionError @@ -440,7 +443,8 @@ class ToxSuite(unittest.TestCase, WrapperMixin): t:callback_group_custom_packet t:callback_group_invite """ - if oTOX_OARGS.network not in ['new', 'newlocal', 'local']: + otox = self.bob + if otox._args.network not in ['new', 'newlocal', 'local']: return port = ts.tox_bootstrapd_port() @@ -492,21 +496,22 @@ class ToxSuite(unittest.TestCase, WrapperMixin): @unittest.skipIf(os.geteuid() != 0, 'must be root') def test_bootstrap_iNmapInfo(self) -> None: # works - global oTOX_OARGS + # if os.environ['USER'] != 'root': # return iStatus = self.bob.self_get_connection_status() LOG.info(f"test_bootstrap_iNmapInfo connected bob iStatus={iStatus}") - if oTOX_OARGS.network in ['new', 'newlocal', 'localnew']: + otox = self.bob + if otox._args.network in ['new', 'newlocal', 'localnew']: lElts = self.lUdp - elif oTOX_OARGS.proxy_port > 0: + elif otox._args.proxy_port > 0: lElts = self.lTcp else: lElts = self.lUdp lRetval = [] random.shuffle(lElts) # assert - ts.bootstrap_iNmapInfo(lElts, oTOX_OARGS, "tcp4", bIS_LOCAL=bIS_LOCAL, iNODES=8) + ts.bootstrap_iNmapInfo(lElts, otox._args, "tcp4", bIS_LOCAL=bIS_LOCAL, iNODES=8) def test_self_get_secret_key(self) -> None: # works """ @@ -593,6 +598,7 @@ class ToxSuite(unittest.TestCase, WrapperMixin): """ t:self_get_udp_port """ + otox = self.bob if hasattr(oTOX_OPTIONS, 'udp_port') and oTOX_OPTIONS.udp_port: o = self.alice.self_get_udp_port() LOG.info('self_get_udp_port alice ' +repr(o)) @@ -893,7 +899,7 @@ class ToxSuite(unittest.TestCase, WrapperMixin): status_message = bytes(MSG, 'utf-8') self.alice.self_set_status_message(status_message) if not self.wait_otox_attrs(self.bob, [sSlot]): - LOG_WARN(f"on_friend_status_message NO {sSlot}") + raise AssertionError(f"on_friend_status_message NO {sSlot}") assert self.bob.friend_get_status_message(self.baid) == MSG, \ f"message={self.bob.friend_get_status_message(self.baid)}" @@ -979,7 +985,6 @@ class ToxSuite(unittest.TestCase, WrapperMixin): else: assert self.bob_add_alice_as_friend() if not self.get_connection_status(): - LOG.warning(f"test_user_status NOT CONNECTED self.get_connection_status") self.loop_until_connected(self.bob) self.bob.callback_friend_status(bobs_on_friend_set_status) @@ -987,8 +992,8 @@ class ToxSuite(unittest.TestCase, WrapperMixin): sSTATUS = TOX_USER_STATUS['BUSY'] self.alice.self_set_status(sSTATUS) if not self.wait_otox_attrs(self.bob, [sSlot]): - # malloc(): unaligned tcache chunk detected - LOG_WARN(f'test_user_status NO {sSlot}') + # malloc(): unaligned tcache chunk detected LOG_WARN + raise AssertionError(f'test_user_status NO {sSlot}') assert self.bob.friend_get_status(self.baid) == TOX_USER_STATUS['BUSY'], \ f"friend_get_status {self.bob.friend_get_status(self.baid)} != {TOX_USER_STATUS['BUSY']}" @@ -1011,7 +1016,6 @@ class ToxSuite(unittest.TestCase, WrapperMixin): t:friend_get_kill_remake t:on_friend_connection_status """ - global oTOX_OARGS sSlot = 'friend_connection_status' setattr(self.bob, sSlot, None) def bobs_on_friend_connection_status(iTox, friend_id, iStatus, *largs): @@ -1022,7 +1026,8 @@ class ToxSuite(unittest.TestCase, WrapperMixin): LOG_ERROR(f"bobs_on_friend_connection_status ERROR {e}") setattr(self.bob, sSlot, True) - opts = oTestsToxOptions(oTOX_OARGS) + otox = self.bob + opts = oTestsToxOptions(otox._args) setattr(self.bob, sSlot, True) try: if self.bob._args.norequest: @@ -1039,7 +1044,7 @@ class ToxSuite(unittest.TestCase, WrapperMixin): LOG.info("test_kill_remake maked alice") if not self.wait_otox_attrs(self.bob, [sSlot]): - LOG_WARN(f'test_kill_remake NO {sSlot}') + raise AssertionError(f'test_kill_remake NO {sSlot}') except AssertionError as e: LOG.error(f"test_kill_remake Failed test {e}") raise @@ -1081,14 +1086,13 @@ class ToxSuite(unittest.TestCase, WrapperMixin): assert self.both_add_as_friend() if not self.get_connection_status(): - LOG.warning(f"test_friend_typing NOT CONNECTED") self.loop_until_connected(self.bob) self.bob.callback_friend_typing(bob_on_friend_typing) self.warn_if_no_cb(self.bob, sSlot) self.alice.self_set_typing(self.abid, False) if not self.wait_otox_attrs(self.bob, [sSlot]): - LOG_WARN(f"bobs_on_friend_typing NO {sSlot}") + raise AssertionError(f"bobs_on_friend_typing NO {sSlot}") except AssertionError as e: LOG.error(f"Failed test {e}") raise @@ -1141,7 +1145,7 @@ class ToxSuite(unittest.TestCase, WrapperMixin): self.warn_if_no_cb(self.bob, sSlot) self.alice.self_set_name(NEWNAME) if not self.wait_otox_attrs(self.bob, [sSlot]): - LOG_WARN(f"bobs_on_friend_name NO {sSlot}") + raise AssertionError(f"bobs_on_friend_name NO {sSlot}") # name=None assert self.bob.friend_get_name(self.baid) == NEWNAME, \ @@ -1161,75 +1165,16 @@ class ToxSuite(unittest.TestCase, WrapperMixin): self.bob.callback_friend_name(None) self.warn_if_cb(self.bob, sSlot) -#! @expectedFail('fails') # This client is currently not connected to the friend. - def test_friend_message(self) -> None: # fails intermittently - """ - t:on_friend_action - t:on_friend_message - t:friend_send_message - """ - - #: Test message - MSG = 'Hi, Bob!' - sSlot = 'friend_message' - - def alices_on_friend_message(iTox, fid:int, msg_type, message, iSize, *largs) -> None: - LOG_DEBUG(f"alices_on_friend_message {fid} {message}") - try: - assert fid == self.alice.abid - assert msg_type == TOX_MESSAGE_TYPE['NORMAL'] - assert str(message, 'UTF-8') == MSG - except Exception as e: - LOG_ERROR(f"alices_on_friend_message EXCEPTION {e}") - else: - LOG_INFO(f"alices_on_friend_message {message}") - setattr(self.alice, sSlot, True) - - setattr(self.alice, sSlot, None) - self.alice.callback_friend_message(None) - try: - if self.bob._args.norequest: - assert self.both_add_as_friend_norequest() - else: - assert self.both_add_as_friend() - assert hasattr(self, 'baid'), \ - "both_add_as_friend_norequest no bob, baid" - assert hasattr(self, 'abid'), \ - "both_add_as_friend_norequest no alice, abid" - if not self.wait_friend_get_connection_status(self.bob, self.baid, n=2*iN): - LOG.warn('baid not connected') - if not self.wait_friend_get_connection_status(self.alice, self.abid, n=2*iN): - LOG.warn('abid not connected') - self.alice.callback_friend_message(alices_on_friend_message) - self.warn_if_no_cb(self.alice, sSlot) - - # dunno - both This client is currently NOT CONNECTED to the friend. - iMesId = self.bob.friend_send_message(self.baid, - TOX_MESSAGE_TYPE['NORMAL'], - bytes(MSG, 'UTF-8')) - assert iMesId >= 0, "iMesId >= 0" - if not self.wait_otox_attrs(self.alice, [sSlot]): - LOG_WARN(f"alices_on_friend_message NO {sSlot}") - except ArgumentError as e: - # ArgumentError('This client is currently NOT CONNECTED to the friend.') - # dunno - LOG.error(f"test_friend_message ArgumentError {e}") - raise - except AssertionError as e: - LOG.error(f"test_friend_message AssertionError {e}") - raise - except Exception as e: - LOG.error(f"test_friend_message EXCEPTION {e}") - raise - finally: - self.alice.callback_friend_message(None) - self.warn_if_cb(self.alice, sSlot) - if hasattr(self, 'baid') and self.baid >= 0: - self.bob.friend_delete(self.baid) - if hasattr(self, 'abid') and self.abid >= 0: - self.alice.friend_delete(self.abid) - +# https://github.com/TokTok/c-toxcore/issues/1338 +# If you node is on the internet, you can check if it works with this test page https://nodes.tox.chat/test. It sends some packets to you node and checks if it gets the correct response back. If it's in a private network, you can telnet into your node telnet 33445 to at least make sure there is something accepting TCP connections on there (I guess nmap works too). +# torsocks telnet 198.199.93.42 33445 +# ERROR torsocks[2573639]: Unable to resolve. Status reply: 4 (in socks5_recv_resolve_reply() at socks5.c:677) +# Trying 198.199.93.42... +# ERROR torsocks[2573639]: General SOCKS server failure (in socks5_recv_connect_reply() at socks5.c:527) +# telnet: connect to address 198.199.93.42: Connection refused +# # This client is currently not connected to the friend. + @expectedFail('fails works! sometimes?') def test_friend_action(self) -> None: # works! sometimes? """ t:on_friend_action @@ -1277,10 +1222,11 @@ class ToxSuite(unittest.TestCase, WrapperMixin): else: assert self.both_add_as_friend() - if not self.wait_friend_get_connection_status(self.bob, self.baid, n=iN): - LOG.warn('baid not connected') - if not self.wait_friend_get_connection_status(self.alice, self.abid, n=iN): - LOG.warn('abid not connected') + if not self.wait_friend_get_connection_status(self.bob, self.baid, n=2*iN): + raise AssertionError(f"bob NOT CONNECTED baid={self.baid}, n={2*iN}") + + if not self.wait_friend_get_connection_status(self.alice, self.abid, n=2*iN): + raise AssertionError(f"alice NOT CONNECTED abid={self.abid}, n={2*iN}") self.bob.callback_friend_read_receipt(their_on_read_reciept) #was their_on_friend_action self.alice.callback_friend_read_receipt(their_on_read_reciept) #was their_on_friend_action @@ -1297,7 +1243,7 @@ class ToxSuite(unittest.TestCase, WrapperMixin): TOX_MESSAGE_TYPE['ACTION'], bytes(ACTION, 'UTF-8')]) if not self.wait_otox_attrs(self.alice, [sSlot]): - LOG_WARN(f"alice test_friend_action NO {sSlot}") + raise AssertionError(f"alice test_friend_action NO {sSlot}") except AssertionError as e: LOG.error(f"Failed test {e}") raise @@ -1315,7 +1261,88 @@ class ToxSuite(unittest.TestCase, WrapperMixin): if hasattr(self, 'abid') and self.abid >= 0: self.alice.friend_delete(self.abid) - @expectedFail('fails') # @unittest.skip('unfinished') + def test_onion_intros(self) -> None: # timeout intermittently + # introduction points are needed for onion services + if self.bob._args.proxy_type == 2: + target = 'zkaan2xfbuxia2wpf7ofnkbz6r5zdbbvxbunvp5g2iebopbfc4iqmbad' + controller = so.oGetStemController(log_level=10) + i = self.bob._args.test_timeout + l = so.lIntroductionPoints(controller, [target], itimeout=i) + if l: + LOG_INFO(f"test_onion_intros len={len(l)}") + else: + LOG_WARN(f"test_onion_intros len={len(l)}") + + # This client is currently not connected to the friend. + @expectedFail('bob NOT CONNECTED baid') # passes clearnet fails tor = no + def test_friend_message(self) -> None: # fails intermittently + """ + t:on_friend_action + t:on_friend_message + t:friend_send_message + """ + # @unittest.skipIf( oTOX_OARGS.proxy_type == 2, 'Fails over Tor') + + #: Test message + MSG = 'Hi, Bob!' + sSlot = 'friend_message' + + def alices_on_friend_message(iTox, fid:int, msg_type, message, iSize, *largs) -> None: + LOG_DEBUG(f"alices_on_friend_message {fid} {message}") + try: + assert fid == self.alice.abid + assert msg_type == TOX_MESSAGE_TYPE['NORMAL'] + assert str(message, 'UTF-8') == MSG + except Exception as e: + LOG_ERROR(f"alices_on_friend_message EXCEPTION {e}") + else: + LOG_INFO(f"alices_on_friend_message {message}") + setattr(self.alice, sSlot, True) + + setattr(self.alice, sSlot, None) + self.alice.callback_friend_message(None) + try: + if self.bob._args.norequest: + assert self.both_add_as_friend_norequest() + else: + assert self.both_add_as_friend() + # should we loop until connection status + if not self.wait_friend_get_connection_status(self.bob, self.baid, n=3*iN): + raise AssertionError(f"bob NOT CONNECTED baid={self.baid}, n={3*iN}") + if not self.wait_friend_get_connection_status(self.alice, self.abid, n=3*iN): + raise AssertionError(f"alice NOT CONNECTED baid={self.abid}, n={3*iN}") + + self.alice.callback_friend_message(alices_on_friend_message) + self.warn_if_no_cb(self.alice, sSlot) + + # dunno - both This client is currently NOT CONNECTED to the friend + # ArgumentError: This client is currently not connected to the friend. + iMesId = self.bob.friend_send_message(self.baid, + TOX_MESSAGE_TYPE['NORMAL'], + bytes(MSG, 'UTF-8')) + assert iMesId >= 0, "iMesId >= 0" + if not self.wait_otox_attrs(self.alice, [sSlot]): + raise AssertionError(f"alices_on_friend_message NO {sSlot}") + except ArgumentError as e: + # ArgumentError('This client is currently NOT CONNECTED to the friend.') + # dunno + LOG.error(f"test_friend_message ArgumentError {e}") + raise + except AssertionError as e: + LOG.error(f"test_friend_message AssertionError {e}") + raise + except Exception as e: + LOG.error(f"test_friend_message EXCEPTION {e}") + raise + finally: + self.alice.callback_friend_message(None) + self.warn_if_cb(self.alice, sSlot) + if hasattr(self, 'baid') and self.baid >= 0: + self.bob.friend_delete(self.baid) + if hasattr(self, 'abid') and self.abid >= 0: + self.alice.friend_delete(self.abid) + + @expectedFail('unfinished') def test_file_transfer(self) -> None: # unfinished """ t:file_send @@ -1526,7 +1553,7 @@ class ToxSuite(unittest.TestCase, WrapperMixin): except: pass - oArgs = oTOX_OARGS + oArgs = self.alice._args opts = oTestsToxOptions(oArgs) opts.savedata_data = data opts.savedata_length = len(data) diff --git a/src/toxygen_wrapper/tests/wrapper_mixin.py b/src/toxygen_wrapper/tests/wrapper_mixin.py index d56f05f..cfeff60 100644 --- a/src/toxygen_wrapper/tests/wrapper_mixin.py +++ b/src/toxygen_wrapper/tests/wrapper_mixin.py @@ -1,5 +1,5 @@ -import ctypes -import hashlib +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + import logging import os import random @@ -9,7 +9,7 @@ import time import threading from ctypes import * from typing import Union, Callable -import tox_wrapper + import tox_wrapper.toxcore_enums_and_consts as enums from tox_wrapper.tox import Tox, UINT32_MAX, ToxError @@ -29,6 +29,7 @@ ADDR_SIZE = 38 * 2 CLIENT_ID_SIZE = 32 * 2 THRESHOLD = 120 # >25 fSOCKET_TIMEOUT = 15.0 +iLOOP_N = 50 iN = 6 @@ -67,7 +68,7 @@ class WrapperMixin(): self.abid in self.alice.self_get_friend_list(): LOG.warn(f"setUp BOB IS ALREADY IN ALICES FRIEND LIST") return False - elif self.alice.self_get_friend_list_size() >= 1: + if self.alice.self_get_friend_list_size() >= 1: LOG.warn(f"setUp ALICE STILL HAS A FRIEND LIST") return False return True @@ -128,6 +129,7 @@ class WrapperMixin(): i = 0 bRet = None while i <= iMax : + i += 1 iRet = otox.group_is_connected(group_number) if iRet == True or iRet == 0: bRet = True @@ -142,8 +144,7 @@ class WrapperMixin(): +" iRet=" +repr(iRet) \ +f" BOBS={otox.mycon_status}" \ +f" last={int(otox.mycon_time)}" ) - i += 1 - self.loop(100) + self.loop(iLOOP_N) else: bRet = False @@ -166,9 +167,11 @@ class WrapperMixin(): t:self_get_connection_status """ i = 0 + num = 4 bRet = None if otox is None: otox = self.bob while i <= otox._args.test_timeout : + i += 1 if (self.alice.mycon_status and self.bob.mycon_status): bRet = True break @@ -195,31 +198,31 @@ class WrapperMixin(): +f" last={int(self.bob.mycon_time)}" ) bRet = True break - i += 1 - self.loop(100) + self.loop(iLOOP_N) else: bRet = False if bRet or \ ( self.bob.self_get_connection_status() != TOX_CONNECTION['NONE'] and \ self.alice.self_get_connection_status() != TOX_CONNECTION['NONE'] ): - LOG.info(f"loop_until_connected returning True {i}" \ + LOG.info(f"loop_until_connected returning True i={i}" \ +f" BOB={self.bob.self_get_connection_status()}" \ +f" ALICE={self.alice.self_get_connection_status()}" \ +f" last={int(self.bob.mycon_time)}" ) return True - else: - otox._args.test_timeout += 5 - LOG.warning(f"loop_until_connected returning False {i}" \ - +f" BOB={self.bob.self_get_connection_status()}" \ - +f" ALICE={self.alice.self_get_connection_status()}" \ - +f" last={int(self.bob.mycon_time)}" ) - return False + + otox._args.test_timeout += 5 + LOG.warning(f"loop_until_connected returning False i={i}" \ + +f" BOB={self.bob.self_get_connection_status()}" \ + +f" ALICE={self.alice.self_get_connection_status()}" \ + +f" last={int(self.bob.mycon_time)}" ) + return False def wait_objs_attr(self, objs: list, attr: str, fsocket_timeout:float = fSOCKET_TIMEOUT) -> bool: i = 0 otox = objs[0] while i <= otox._args.test_timeout: + i += 1 if i % 5 == 0: num = None j = 0 @@ -228,8 +231,7 @@ class WrapperMixin(): LOG.debug(f"wait_objs_attr {objs} for {attr} {i}") if all([getattr(obj, attr) for obj in objs]): return True - self.loop(100) - i += 1 + self.loop(iLOOP_N) else: otox._args.test_timeout += 1 LOG.warn(f"wait_objs_attr for {attr} i >= {otox._args.test_timeout}") @@ -241,6 +243,7 @@ class WrapperMixin(): i = 0 otox = obj while i <= otox._args.test_timeout: + i += 1 if i % 5 == 0: num = None j = 0 @@ -255,8 +258,7 @@ class WrapperMixin(): +f" last={int(obj.mycon_time)}") if all([getattr(obj, attr) is not None for attr in attrs]): return True - self.loop(100) - i += 1 + self.loop(iLOOP_N) else: LOG.warning(f"wait_otox_attrs i >= {otox._args.test_timeout} attrs={attrs} results={[getattr(obj, attr) for attr in attrs]}") @@ -266,6 +268,7 @@ class WrapperMixin(): i = 0 oRet = None while i <= self.bob._args.test_timeout: + i += 1 if i % 5 == 0: # every 10 sec add another random nodes to bootstrap j = i//10 + 1 @@ -287,7 +290,6 @@ class WrapperMixin(): LOG.warning(f"wait_ensure_exec EXCEPTION {e}") return False sleep(3) - i += 1 else: LOG.error(f"wait_ensure_exec i >= {1*self.bob._args.test_timeout}") return False @@ -324,11 +326,11 @@ class WrapperMixin(): def both_add_as_friend(self) -> bool: if self.bob._args.norequest: - assert self.bob_add_alice_as_friend() - assert self.alice_add_bob_as_friend_norequest() - else: assert self.bob_add_alice_as_friend_norequest() assert self.alice_add_bob_as_friend_norequest() + else: + assert self.bob_add_alice_as_friend() + assert self.alice_add_bob_as_friend() if not hasattr(self, 'baid') or self.baid < 0: LOG.warn("both_add_as_friend no bob, baid") if not hasattr(self, 'abid') or self.abid < 0: @@ -340,9 +342,9 @@ class WrapperMixin(): assert self.bob_add_alice_as_friend_norequest() if self.bAliceNeedAddBob(): assert self.alice_add_bob_as_friend_norequest() - if not hasattr(self, 'baid') or self.baid < 0: + if not hasattr(self.bob, 'baid') or self.bob.baid < 0: LOG.warn("both_add_as_friend_norequest no bob, baid") - if not hasattr(self, 'abid') or self.abid < 0: + if not hasattr(self.alice, 'abid') or self.alice.abid < 0: LOG.warn("both_add_as_friend_norequest no alice, abid") #: Test last online @@ -462,7 +464,7 @@ class WrapperMixin(): sSlot = 'friend_status' setattr(self.bob, sSlot, None) def bobs_on_friend_status(iTox, friend_id, iStatus, *largs) -> None: - LOG_INFO(f"bobs_on_friend_status {friend_id} ?>=0" +repr(iStatus)) + LOG_INFO(f"bobs_on_friend_status {friend_id} ?>=0 iS={iStatus}") setattr(self.bob, sSlot, False) sSlot = 'friend_conn_status' @@ -474,13 +476,12 @@ class WrapperMixin(): sSlot = 'friend_status' setattr(self.alice, sSlot, None) def alices_on_friend_status(iTox, friend_id, iStatus, *largs) -> None: - LOG_INFO(f"alices_on_friend_status {friend_id} ?>=0 " +repr(iStatus)) + LOG_INFO(f"alices_on_friend_status {friend_id} ?>=0 iS={iStatus}") setattr(self.alice, sSlot, False) try: # need a friend connected? if not self.get_connection_status(): - LOG.warning(f"test_groups_join NOT CONNECTED") self.loop_until_connected(self.bob) LOG.info("bob_add_alice_as_friend_and_status waiting for alice connections") if not self.wait_otox_attrs(self.alice, @@ -661,16 +662,16 @@ class WrapperMixin(): def wait_friend_get_connection_status(self, otox, fid:int, n:int = iN) -> int: i = 0 while i < n: + i += 1 iRet = otox.friend_get_connection_status(fid) if iRet == TOX_CONNECTION['NONE']: -# LOG.debug(f"wait_friend_get_connection_status NOT CONNECTED i={i} {iRet}") + LOG.debug(f"wait_friend_get_connection_status NOT CONNECTED i={i} fid={fid} {iRet}") self.loop_until_connected(otox) else: - LOG.info(f"wait_friend_get_connection_status {iRet}") + LOG.info(f"wait_friend_get_connection_status fid={fid} {iRet}") return True - i += 1 else: - LOG.error(f"wait_friend_get_connection_status n={n}") + LOG.error(f"wait_friend_get_connection_status fid={fid} n={n}") return False def warn_if_no_cb(self, alice, sSlot:str) -> None: