update
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run

This commit is contained in:
emdee@spm.plastiras.org 2024-02-10 20:43:34 +00:00
parent 4fc9a23961
commit eb7287e659
6 changed files with 226 additions and 192 deletions

View File

@ -16,6 +16,7 @@ check::
install:: install::
${PIP_EXE_MSYS} --python ${PYTHON_EXE_MSYS} install \ ${PIP_EXE_MSYS} --python ${PYTHON_EXE_MSYS} install \
--no-deps \
--target ${PREFIX}/lib/python${PYTHON_MINOR}/site-packages/ \ --target ${PREFIX}/lib/python${PYTHON_MINOR}/site-packages/ \
--upgrade . --upgrade .
@ -30,7 +31,9 @@ test::
test_direct:: test_direct::
cp -p ${HOME}/.config/tox/DHTnodes.json /tmp/toxygen_nodes.json cp -p ${HOME}/.config/tox/DHTnodes.json /tmp/toxygen_nodes.json
PYTHONPATH=$${PWD}/src \ PYTHONPATH=$${PWD}/src \
TOR_CONTROLLER_PASSWORD=${PASS} \
sudo -u bin $(PYTHON_EXE_MSYS) src/toxygen_wrapper/tests/tests_wrapper.py \ sudo -u bin $(PYTHON_EXE_MSYS) src/toxygen_wrapper/tests/tests_wrapper.py \
--norequest=True \
--socket_timeout=10.0 \ --socket_timeout=10.0 \
--test_timeout=${iTEST_TIMEOUT} \ --test_timeout=${iTEST_TIMEOUT} \
--nodes_json=/tmp/toxygen_nodes.json \ --nodes_json=/tmp/toxygen_nodes.json \
@ -39,7 +42,9 @@ test_direct::
test_proxy:: test_proxy::
PYTHONPATH=$${PWD}/src \ PYTHONPATH=$${PWD}/src \
TOR_CONTROLLER_PASSWORD=${PASS} \
${PYTHON_EXE_MSYS} src/toxygen_wrapper/tests/tests_wrapper.py \ ${PYTHON_EXE_MSYS} src/toxygen_wrapper/tests/tests_wrapper.py \
--norequest=True \
--socket_timeout=15.0 \ --socket_timeout=15.0 \
--test_timeout=${iTEST_TIMEOUT} \ --test_timeout=${iTEST_TIMEOUT} \
--proxy_host=127.0.0.1 \ --proxy_host=127.0.0.1 \

View File

@ -8,7 +8,7 @@ import urllib
import traceback import traceback
global LOG global LOG
LOG = logging.getLogger('app.'+'ts') LOG = logging.getLogger('TestS')
try: try:
import pycurl import pycurl

View File

@ -1,4 +1,7 @@
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- # -*- 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 getpass
import os import os
@ -9,13 +12,8 @@ import socket
import sys import sys
import time import time
from typing import Union, Callable, Union 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 import stem
from stem.connection import MissingPassword from stem.connection import MissingPassword
from stem.control import Controller from stem.control import Controller
@ -23,17 +21,17 @@ else:
global LOG global LOG
import logging import logging
import warnings from toxygen_wrapper.tests.support_http import bAreWeConnected
warnings.filterwarnings('ignore') warnings.filterwarnings('ignore')
LOG = logging.getLogger() LOG = logging.getLogger('TestS')
bHAVE_TORR = shutil.which('tor-resolve') bHAVE_TORR = shutil.which('tor-resolve')
oSTEM_CONTROLER = None
yKNOWN_ONIONS = """ yKNOWN_ONIONS = """
- facebookwkhpilnemxj7asaniu7vnjjbiltxjqhye3mhbshg7kx5tfyd # facebook - facebookwkhpilnemxj7asaniu7vnjjbiltxjqhye3mhbshg7kx5tfyd # facebook
- duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad # ddg - duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad # ddg
- zkaan2xfbuxia2wpf7ofnkbz6r5zdbbvxbunvp5g2iebopbfc4iqmbad # hks - zkaan2xfbuxia2wpf7ofnkbz6r5zdbbvxbunvp5g2iebopbfc4iqmbad # keys.openpgp
""" """
# grep -B 1 '<li><a href="' /tmp/tor.html |sed -e 's/<li><a href="http:../ - /' -e 's/.onion.*//' -e 's/<li id=./ # /' -e 's/".*//' -e '/^--/d' -e '/<li id/d' # grep -B 1 '<li><a href="' /tmp/tor.html |sed -e 's/<li><a href="http:../ - /' -e 's/.onion.*//' -e 's/<li id=./ # /' -e 's/".*//' -e '/^--/d' -e '/<li id/d'
# This will slow things down 1-2 min each # This will slow things down 1-2 min each
@ -225,19 +223,28 @@ yKNOWN_NODNS = """
# - w.digidow.eu # - w.digidow.eu
# - w.cccs.de # - w.cccs.de
def oMakeController(sSock:str = '', port:int = 9051): def oMakeController(sSock:str = '', port:int = 9051, password:[str,None] = None):
import getpass global oSTEM_CONTROLER
from getpass import unix_getpass
if sSock and os.path.exists(sSock): if sSock and os.path.exists(sSock):
controller = Controller.from_socket_file(path=sSock) controller = Controller.from_socket_file(path=sSock)
else: else:
controller = Controller.from_port(port=port) controller = Controller.from_port(port=port)
try:
controller.authenticate()
except (Exception, MissingPassword):
if password is None:
password = os.environ.get('TOR_CONTROLLER_PASSWORD', '')
if password:
p = password
else:
sys.stdout.flush() sys.stdout.flush()
p = getpass.unix_getpass(prompt='Controller Password: ', stream=sys.stderr) p = unix_getpass(prompt='Controller Password: ', stream=sys.stderr)
controller.authenticate(p) controller.authenticate(p)
oSTEM_CONTROLER = controller
return controller return controller
oSTEM_CONTROLER = None def oGetStemController(log_level:int = 10, sock_or_pair:str = '/run/tor/control', password:[str,None] = None):
def oGetStemController(log_level:int = 10, sock_or_pair:str = '/run/tor/control'):
global oSTEM_CONTROLER global oSTEM_CONTROLER
if oSTEM_CONTROLER: return oSTEM_CONTROLER if oSTEM_CONTROLER: return oSTEM_CONTROLER
@ -262,6 +269,11 @@ def oGetStemController(log_level:int = 10, sock_or_pair:str = '/run/tor/control'
try: try:
controller.authenticate() controller.authenticate()
except (Exception, MissingPassword): except (Exception, MissingPassword):
if password is None:
password = os.environ.get('TOR_CONTROLLER_PASSWORD', '')
if password:
p = password
else:
sys.stdout.flush() sys.stdout.flush()
p = getpass.unix_getpass(prompt='Controller Password: ', stream=sys.stderr) p = getpass.unix_getpass(prompt='Controller Password: ', stream=sys.stderr)
controller.authenticate(p) controller.authenticate(p)
@ -269,28 +281,15 @@ def oGetStemController(log_level:int = 10, sock_or_pair:str = '/run/tor/control'
LOG.debug(f"{controller}") LOG.debug(f"{controller}")
return oSTEM_CONTROLER return oSTEM_CONTROLER
def bAreWeConnected() -> bool: def sMapaddressResolv(target:str, iPort:int = 9051, log_level:int = 10, password:[str,None] = None) -> str:
# 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:
if not stem: if not stem:
LOG.warn('please install the stem Python package') LOG.warn('please install the stem Python package')
return '' return ''
try: try:
controller = oGetStemController(log_level=log_level) controller = oGetStemController(log_level=log_level, password=password)
map_dict = {"0.0.0.0": target} map_dict = {"0.0.0.0": target}
map_ret = controller.map_address(map_dict) map_ret = controller.map_address(map_dict)
return map_ret return map_ret
except Exception as e: except Exception as e:
LOG.exception(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: def vwait_for_controller(controller, wait_boot:int = 10) -> None:
if bAreWeConnected() is False: if bAreWeConnected() is False:
raise SystemExit("we are not connected") raise RuntimeError("we are not connected")
percent = i = 0 percent = i = 0
# You can call this while boostrapping # You can call this while boostrapping
while percent < 100 and i < wait_boot: 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)) res = ''.join('{:02x}'.format(raw_id[i]) for i in range(length))
return res.upper() 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 """now working !!! stem 1.8.x timeout must be huge >120
'Provides the descriptor for a hidden service. The **address** is the 'Provides the descriptor for a hidden service. The **address** is the
'.onion' address of the hidden service ' '.onion' address of the hidden service '
What about Services? What about Services?
""" """
if lOnions is None: lOnions = []
try: try:
from cryptography.utils import int_from_bytes from cryptography.utils import int_from_bytes
except ImportError: except ImportError:
import cryptography.utils import cryptography.utils
# guessing - not in the current cryptography but stem expects it # guessing - not in the current cryptography but stem expects it
def int_from_bytes(**args): return int.to_bytes(*args) def int_from_bytes(**args): return int.to_bytes(*args)
cryptography.utils.int_from_bytes = int_from_bytes 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]: if type(lOnions) not in [set, tuple, list]:
lOnions = list(lOnions) lOnions = list(lOnions)
if controller is None: if controller is None:
controller = oGetStemController(log_level=log_level) controller = oGetStemController(log_level=log_level, password=password)
l = [] l = []
for elt in lOnions: for elt in lOnions:
LOG.info(f"controller.get_hidden_service_descriptor {elt}") 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') print('VirtualAddrNetworkIPv4 172.16.0.0/12')
return 0 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 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') LOG.debug('lExcludeExitNodes')
try: try:
controller = oGetStemController(log_level=log_level) controller = oGetStemController(log_level=log_level, password=password)
# generator # generator
relays = controller.get_server_descriptors() relays = controller.get_server_descriptors()
except Exception as e: except Exception as e:
@ -568,6 +567,6 @@ def lExitExcluder(oArgs, iPort:int = 9051, log_level:int = 10) -> list:
return exit_excludelist return exit_excludelist
if __name__ == '__main__': if __name__ == '__main__':
target = 'duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad' target = 'zkaan2xfbuxia2wpf7ofnkbz6r5zdbbvxbunvp5g2iebopbfc4iqmbad'
controller = oGetStemController(log_level=10) controller = oGetStemController(log_level=10)
lIntroductionPoints(controller, [target], itimeout=120) lIntroductionPoints(controller, [target], itimeout=120)

View File

@ -49,7 +49,7 @@ from tox_wrapper.tests.support_onions import (is_valid_fingerprint,
# LOG=util.log # LOG=util.log
global LOG global LOG
LOG = logging.getLogger() LOG = logging.getLogger('TestS')
# callbacks can be called in any thread so were being careful # callbacks can be called in any thread so were being careful
def LOG_ERROR(l): print('EROR< '+l) def LOG_ERROR(l): print('EROR< '+l)
@ -148,6 +148,8 @@ def assert_main_thread() -> None:
from qtpy.QtWidgets import QApplication from qtpy.QtWidgets import QApplication
# this "instance" method is very useful! # this "instance" method is very useful!
app_instance = QtWidgets.QApplication.instance()
if app_instance:
app_thread = QtWidgets.QApplication.instance().thread() app_thread = QtWidgets.QApplication.instance().thread()
curr_thread = QtCore.QThread.currentThread() curr_thread = QtCore.QThread.currentThread()
if app_thread != curr_thread: if app_thread != curr_thread:

View File

@ -23,21 +23,24 @@
"""Originaly from https://github.com/oxij/PyTox c-toxcore-02 branch """Originaly from https://github.com/oxij/PyTox c-toxcore-02 branch
which itself was forked from https://github.com/aitjcize/PyTox/ which itself was forked from https://github.com/aitjcize/PyTox/
Modified to work with toxygen_wrapper 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 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 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. 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 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 wait in each test to get connected on tests that require connectivity,
not unusual, but less for directly connected. 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, 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 triple. 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,8 +88,8 @@ except ImportError as e:
import tox_wrapper import tox_wrapper
import tox_wrapper.toxcore_enums_and_consts as enums import tox_wrapper.toxcore_enums_and_consts as enums
from tox_wrapper.tox import Tox, UINT32_MAX, ToxError from tox_wrapper.tox import Tox, UINT32_MAX, ToxError
from tox_wrapper.toxcore_enums_and_consts import (TOX_ADDRESS_SIZE,
from tox_wrapper.toxcore_enums_and_consts import (TOX_ADDRESS_SIZE, TOX_CONNECTION, TOX_CONNECTION,
TOX_FILE_CONTROL, TOX_FILE_CONTROL,
TOX_MESSAGE_TYPE, TOX_MESSAGE_TYPE,
TOX_SECRET_KEY_SIZE, TOX_SECRET_KEY_SIZE,
@ -94,8 +97,12 @@ from tox_wrapper.toxcore_enums_and_consts import (TOX_ADDRESS_SIZE, TOX_CONNECTI
try: try:
import support_testing as ts import support_testing as ts
import support_onions as so
except ImportError: except ImportError:
import tox_wrapper.tests.support_testing as ts import tox_wrapper.tests.support_testing as ts
import tox_wrapper.tests.support_onions as so
from wrapper_mixin import WrapperMixin
try: try:
from tests.toxygen_tests import test_sound_notification from tests.toxygen_tests import test_sound_notification
@ -105,7 +112,6 @@ except ImportError:
# from PyQt5 import QtCore # from PyQt5 import QtCore
import time import time
sleep = time.sleep sleep = time.sleep
global LOG global LOG
@ -248,7 +254,6 @@ def prepare(self):
LOG_WARN(f"bobs_on_self_connection_status DISAGREE {status}") LOG_WARN(f"bobs_on_self_connection_status DISAGREE {status}")
def alices_on_self_connection_status(iTox, connection_state: int, *args) -> None: def alices_on_self_connection_status(iTox, connection_state: int, *args) -> None:
global oTOX_OARGS
#FixMe connection_num #FixMe connection_num
status = connection_state status = connection_state
self.alice.dht_connected = status self.alice.dht_connected = status
@ -289,8 +294,6 @@ def prepare(self):
LOG.warning(f"doOnce not local and NOT CONNECTED") LOG.warning(f"doOnce not local and NOT CONNECTED")
return [bob, alice] return [bob, alice]
from wrapper_mixin import WrapperMixin
class ToxSuite(unittest.TestCase, WrapperMixin): class ToxSuite(unittest.TestCase, WrapperMixin):
failureException = AssertionError failureException = AssertionError
@ -440,7 +443,8 @@ class ToxSuite(unittest.TestCase, WrapperMixin):
t:callback_group_custom_packet t:callback_group_custom_packet
t:callback_group_invite 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 return
port = ts.tox_bootstrapd_port() port = ts.tox_bootstrapd_port()
@ -492,21 +496,22 @@ class ToxSuite(unittest.TestCase, WrapperMixin):
@unittest.skipIf(os.geteuid() != 0, 'must be root') @unittest.skipIf(os.geteuid() != 0, 'must be root')
def test_bootstrap_iNmapInfo(self) -> None: # works def test_bootstrap_iNmapInfo(self) -> None: # works
global oTOX_OARGS
# if os.environ['USER'] != 'root': # if os.environ['USER'] != 'root':
# return # return
iStatus = self.bob.self_get_connection_status() iStatus = self.bob.self_get_connection_status()
LOG.info(f"test_bootstrap_iNmapInfo connected bob iStatus={iStatus}") 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 lElts = self.lUdp
elif oTOX_OARGS.proxy_port > 0: elif otox._args.proxy_port > 0:
lElts = self.lTcp lElts = self.lTcp
else: else:
lElts = self.lUdp lElts = self.lUdp
lRetval = [] lRetval = []
random.shuffle(lElts) random.shuffle(lElts)
# assert # 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 def test_self_get_secret_key(self) -> None: # works
""" """
@ -593,6 +598,7 @@ class ToxSuite(unittest.TestCase, WrapperMixin):
""" """
t:self_get_udp_port t:self_get_udp_port
""" """
otox = self.bob
if hasattr(oTOX_OPTIONS, 'udp_port') and oTOX_OPTIONS.udp_port: if hasattr(oTOX_OPTIONS, 'udp_port') and oTOX_OPTIONS.udp_port:
o = self.alice.self_get_udp_port() o = self.alice.self_get_udp_port()
LOG.info('self_get_udp_port alice ' +repr(o)) LOG.info('self_get_udp_port alice ' +repr(o))
@ -893,7 +899,7 @@ class ToxSuite(unittest.TestCase, WrapperMixin):
status_message = bytes(MSG, 'utf-8') status_message = bytes(MSG, 'utf-8')
self.alice.self_set_status_message(status_message) self.alice.self_set_status_message(status_message)
if not self.wait_otox_attrs(self.bob, [sSlot]): 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, \ assert self.bob.friend_get_status_message(self.baid) == MSG, \
f"message={self.bob.friend_get_status_message(self.baid)}" f"message={self.bob.friend_get_status_message(self.baid)}"
@ -979,7 +985,6 @@ class ToxSuite(unittest.TestCase, WrapperMixin):
else: else:
assert self.bob_add_alice_as_friend() assert self.bob_add_alice_as_friend()
if not self.get_connection_status(): 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.loop_until_connected(self.bob)
self.bob.callback_friend_status(bobs_on_friend_set_status) self.bob.callback_friend_status(bobs_on_friend_set_status)
@ -987,8 +992,8 @@ class ToxSuite(unittest.TestCase, WrapperMixin):
sSTATUS = TOX_USER_STATUS['BUSY'] sSTATUS = TOX_USER_STATUS['BUSY']
self.alice.self_set_status(sSTATUS) self.alice.self_set_status(sSTATUS)
if not self.wait_otox_attrs(self.bob, [sSlot]): if not self.wait_otox_attrs(self.bob, [sSlot]):
# malloc(): unaligned tcache chunk detected # malloc(): unaligned tcache chunk detected LOG_WARN
LOG_WARN(f'test_user_status NO {sSlot}') raise AssertionError(f'test_user_status NO {sSlot}')
assert self.bob.friend_get_status(self.baid) == TOX_USER_STATUS['BUSY'], \ 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']}" 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:friend_get_kill_remake
t:on_friend_connection_status t:on_friend_connection_status
""" """
global oTOX_OARGS
sSlot = 'friend_connection_status' sSlot = 'friend_connection_status'
setattr(self.bob, sSlot, None) setattr(self.bob, sSlot, None)
def bobs_on_friend_connection_status(iTox, friend_id, iStatus, *largs): 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}") LOG_ERROR(f"bobs_on_friend_connection_status ERROR {e}")
setattr(self.bob, sSlot, True) setattr(self.bob, sSlot, True)
opts = oTestsToxOptions(oTOX_OARGS) otox = self.bob
opts = oTestsToxOptions(otox._args)
setattr(self.bob, sSlot, True) setattr(self.bob, sSlot, True)
try: try:
if self.bob._args.norequest: if self.bob._args.norequest:
@ -1039,7 +1044,7 @@ class ToxSuite(unittest.TestCase, WrapperMixin):
LOG.info("test_kill_remake maked alice") LOG.info("test_kill_remake maked alice")
if not self.wait_otox_attrs(self.bob, [sSlot]): 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: except AssertionError as e:
LOG.error(f"test_kill_remake Failed test {e}") LOG.error(f"test_kill_remake Failed test {e}")
raise raise
@ -1081,14 +1086,13 @@ class ToxSuite(unittest.TestCase, WrapperMixin):
assert self.both_add_as_friend() assert self.both_add_as_friend()
if not self.get_connection_status(): if not self.get_connection_status():
LOG.warning(f"test_friend_typing NOT CONNECTED")
self.loop_until_connected(self.bob) self.loop_until_connected(self.bob)
self.bob.callback_friend_typing(bob_on_friend_typing) self.bob.callback_friend_typing(bob_on_friend_typing)
self.warn_if_no_cb(self.bob, sSlot) self.warn_if_no_cb(self.bob, sSlot)
self.alice.self_set_typing(self.abid, False) self.alice.self_set_typing(self.abid, False)
if not self.wait_otox_attrs(self.bob, [sSlot]): 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: except AssertionError as e:
LOG.error(f"Failed test {e}") LOG.error(f"Failed test {e}")
raise raise
@ -1141,7 +1145,7 @@ class ToxSuite(unittest.TestCase, WrapperMixin):
self.warn_if_no_cb(self.bob, sSlot) self.warn_if_no_cb(self.bob, sSlot)
self.alice.self_set_name(NEWNAME) self.alice.self_set_name(NEWNAME)
if not self.wait_otox_attrs(self.bob, [sSlot]): 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 # name=None
assert self.bob.friend_get_name(self.baid) == NEWNAME, \ 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.bob.callback_friend_name(None)
self.warn_if_cb(self.bob, sSlot) self.warn_if_cb(self.bob, sSlot)
#! @expectedFail('fails') # This client is currently not connected to the friend. # https://github.com/TokTok/c-toxcore/issues/1338
def test_friend_message(self) -> None: # fails intermittently # 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 <ip> 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
t:on_friend_action # ERROR torsocks[2573639]: Unable to resolve. Status reply: 4 (in socks5_recv_resolve_reply() at socks5.c:677)
t:on_friend_message # Trying 198.199.93.42...
t:friend_send_message # 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
#
#: 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)
# This client is currently not connected to the friend. # This client is currently not connected to the friend.
@expectedFail('fails works! sometimes?')
def test_friend_action(self) -> None: # works! sometimes? def test_friend_action(self) -> None: # works! sometimes?
""" """
t:on_friend_action t:on_friend_action
@ -1277,10 +1222,11 @@ class ToxSuite(unittest.TestCase, WrapperMixin):
else: else:
assert self.both_add_as_friend() assert self.both_add_as_friend()
if not self.wait_friend_get_connection_status(self.bob, self.baid, n=iN): if not self.wait_friend_get_connection_status(self.bob, self.baid, n=2*iN):
LOG.warn('baid not connected') 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=iN):
LOG.warn('abid not connected') 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.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 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'], TOX_MESSAGE_TYPE['ACTION'],
bytes(ACTION, 'UTF-8')]) bytes(ACTION, 'UTF-8')])
if not self.wait_otox_attrs(self.alice, [sSlot]): 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: except AssertionError as e:
LOG.error(f"Failed test {e}") LOG.error(f"Failed test {e}")
raise raise
@ -1315,7 +1261,88 @@ class ToxSuite(unittest.TestCase, WrapperMixin):
if hasattr(self, 'abid') and self.abid >= 0: if hasattr(self, 'abid') and self.abid >= 0:
self.alice.friend_delete(self.abid) 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 def test_file_transfer(self) -> None: # unfinished
""" """
t:file_send t:file_send
@ -1526,7 +1553,7 @@ class ToxSuite(unittest.TestCase, WrapperMixin):
except: except:
pass pass
oArgs = oTOX_OARGS oArgs = self.alice._args
opts = oTestsToxOptions(oArgs) opts = oTestsToxOptions(oArgs)
opts.savedata_data = data opts.savedata_data = data
opts.savedata_length = len(data) opts.savedata_length = len(data)

View File

@ -1,5 +1,5 @@
import ctypes # -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
import hashlib
import logging import logging
import os import os
import random import random
@ -9,7 +9,7 @@ import time
import threading import threading
from ctypes import * from ctypes import *
from typing import Union, Callable from typing import Union, Callable
import tox_wrapper
import tox_wrapper.toxcore_enums_and_consts as enums import tox_wrapper.toxcore_enums_and_consts as enums
from tox_wrapper.tox import Tox, UINT32_MAX, ToxError from tox_wrapper.tox import Tox, UINT32_MAX, ToxError
@ -29,6 +29,7 @@ ADDR_SIZE = 38 * 2
CLIENT_ID_SIZE = 32 * 2 CLIENT_ID_SIZE = 32 * 2
THRESHOLD = 120 # >25 THRESHOLD = 120 # >25
fSOCKET_TIMEOUT = 15.0 fSOCKET_TIMEOUT = 15.0
iLOOP_N = 50
iN = 6 iN = 6
@ -67,7 +68,7 @@ class WrapperMixin():
self.abid in self.alice.self_get_friend_list(): self.abid in self.alice.self_get_friend_list():
LOG.warn(f"setUp BOB IS ALREADY IN ALICES FRIEND LIST") LOG.warn(f"setUp BOB IS ALREADY IN ALICES FRIEND LIST")
return False 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") LOG.warn(f"setUp ALICE STILL HAS A FRIEND LIST")
return False return False
return True return True
@ -128,6 +129,7 @@ class WrapperMixin():
i = 0 i = 0
bRet = None bRet = None
while i <= iMax : while i <= iMax :
i += 1
iRet = otox.group_is_connected(group_number) iRet = otox.group_is_connected(group_number)
if iRet == True or iRet == 0: if iRet == True or iRet == 0:
bRet = True bRet = True
@ -142,8 +144,7 @@ class WrapperMixin():
+" iRet=" +repr(iRet) \ +" iRet=" +repr(iRet) \
+f" BOBS={otox.mycon_status}" \ +f" BOBS={otox.mycon_status}" \
+f" last={int(otox.mycon_time)}" ) +f" last={int(otox.mycon_time)}" )
i += 1 self.loop(iLOOP_N)
self.loop(100)
else: else:
bRet = False bRet = False
@ -166,9 +167,11 @@ class WrapperMixin():
t:self_get_connection_status t:self_get_connection_status
""" """
i = 0 i = 0
num = 4
bRet = None bRet = None
if otox is None: otox = self.bob if otox is None: otox = self.bob
while i <= otox._args.test_timeout : while i <= otox._args.test_timeout :
i += 1
if (self.alice.mycon_status and self.bob.mycon_status): if (self.alice.mycon_status and self.bob.mycon_status):
bRet = True bRet = True
break break
@ -195,22 +198,21 @@ class WrapperMixin():
+f" last={int(self.bob.mycon_time)}" ) +f" last={int(self.bob.mycon_time)}" )
bRet = True bRet = True
break break
i += 1 self.loop(iLOOP_N)
self.loop(100)
else: else:
bRet = False bRet = False
if bRet or \ if bRet or \
( self.bob.self_get_connection_status() != TOX_CONNECTION['NONE'] and \ ( self.bob.self_get_connection_status() != TOX_CONNECTION['NONE'] and \
self.alice.self_get_connection_status() != TOX_CONNECTION['NONE'] ): 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" BOB={self.bob.self_get_connection_status()}" \
+f" ALICE={self.alice.self_get_connection_status()}" \ +f" ALICE={self.alice.self_get_connection_status()}" \
+f" last={int(self.bob.mycon_time)}" ) +f" last={int(self.bob.mycon_time)}" )
return True return True
else:
otox._args.test_timeout += 5 otox._args.test_timeout += 5
LOG.warning(f"loop_until_connected returning False {i}" \ LOG.warning(f"loop_until_connected returning False i={i}" \
+f" BOB={self.bob.self_get_connection_status()}" \ +f" BOB={self.bob.self_get_connection_status()}" \
+f" ALICE={self.alice.self_get_connection_status()}" \ +f" ALICE={self.alice.self_get_connection_status()}" \
+f" last={int(self.bob.mycon_time)}" ) +f" last={int(self.bob.mycon_time)}" )
@ -220,6 +222,7 @@ class WrapperMixin():
i = 0 i = 0
otox = objs[0] otox = objs[0]
while i <= otox._args.test_timeout: while i <= otox._args.test_timeout:
i += 1
if i % 5 == 0: if i % 5 == 0:
num = None num = None
j = 0 j = 0
@ -228,8 +231,7 @@ class WrapperMixin():
LOG.debug(f"wait_objs_attr {objs} for {attr} {i}") LOG.debug(f"wait_objs_attr {objs} for {attr} {i}")
if all([getattr(obj, attr) for obj in objs]): if all([getattr(obj, attr) for obj in objs]):
return True return True
self.loop(100) self.loop(iLOOP_N)
i += 1
else: else:
otox._args.test_timeout += 1 otox._args.test_timeout += 1
LOG.warn(f"wait_objs_attr for {attr} i >= {otox._args.test_timeout}") LOG.warn(f"wait_objs_attr for {attr} i >= {otox._args.test_timeout}")
@ -241,6 +243,7 @@ class WrapperMixin():
i = 0 i = 0
otox = obj otox = obj
while i <= otox._args.test_timeout: while i <= otox._args.test_timeout:
i += 1
if i % 5 == 0: if i % 5 == 0:
num = None num = None
j = 0 j = 0
@ -255,8 +258,7 @@ class WrapperMixin():
+f" last={int(obj.mycon_time)}") +f" last={int(obj.mycon_time)}")
if all([getattr(obj, attr) is not None for attr in attrs]): if all([getattr(obj, attr) is not None for attr in attrs]):
return True return True
self.loop(100) self.loop(iLOOP_N)
i += 1
else: else:
LOG.warning(f"wait_otox_attrs i >= {otox._args.test_timeout} attrs={attrs} results={[getattr(obj, attr) for attr in attrs]}") 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 i = 0
oRet = None oRet = None
while i <= self.bob._args.test_timeout: while i <= self.bob._args.test_timeout:
i += 1
if i % 5 == 0: if i % 5 == 0:
# every 10 sec add another random nodes to bootstrap # every 10 sec add another random nodes to bootstrap
j = i//10 + 1 j = i//10 + 1
@ -287,7 +290,6 @@ class WrapperMixin():
LOG.warning(f"wait_ensure_exec EXCEPTION {e}") LOG.warning(f"wait_ensure_exec EXCEPTION {e}")
return False return False
sleep(3) sleep(3)
i += 1
else: else:
LOG.error(f"wait_ensure_exec i >= {1*self.bob._args.test_timeout}") LOG.error(f"wait_ensure_exec i >= {1*self.bob._args.test_timeout}")
return False return False
@ -324,11 +326,11 @@ class WrapperMixin():
def both_add_as_friend(self) -> bool: def both_add_as_friend(self) -> bool:
if self.bob._args.norequest: 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.bob_add_alice_as_friend_norequest()
assert self.alice_add_bob_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: if not hasattr(self, 'baid') or self.baid < 0:
LOG.warn("both_add_as_friend no bob, baid") LOG.warn("both_add_as_friend no bob, baid")
if not hasattr(self, 'abid') or self.abid < 0: if not hasattr(self, 'abid') or self.abid < 0:
@ -340,9 +342,9 @@ class WrapperMixin():
assert self.bob_add_alice_as_friend_norequest() assert self.bob_add_alice_as_friend_norequest()
if self.bAliceNeedAddBob(): if self.bAliceNeedAddBob():
assert self.alice_add_bob_as_friend_norequest() 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") 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") LOG.warn("both_add_as_friend_norequest no alice, abid")
#: Test last online #: Test last online
@ -462,7 +464,7 @@ class WrapperMixin():
sSlot = 'friend_status' sSlot = 'friend_status'
setattr(self.bob, sSlot, None) setattr(self.bob, sSlot, None)
def bobs_on_friend_status(iTox, friend_id, iStatus, *largs) -> 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) setattr(self.bob, sSlot, False)
sSlot = 'friend_conn_status' sSlot = 'friend_conn_status'
@ -474,13 +476,12 @@ class WrapperMixin():
sSlot = 'friend_status' sSlot = 'friend_status'
setattr(self.alice, sSlot, None) setattr(self.alice, sSlot, None)
def alices_on_friend_status(iTox, friend_id, iStatus, *largs) -> 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) setattr(self.alice, sSlot, False)
try: try:
# need a friend connected? # need a friend connected?
if not self.get_connection_status(): if not self.get_connection_status():
LOG.warning(f"test_groups_join NOT CONNECTED")
self.loop_until_connected(self.bob) self.loop_until_connected(self.bob)
LOG.info("bob_add_alice_as_friend_and_status waiting for alice connections") LOG.info("bob_add_alice_as_friend_and_status waiting for alice connections")
if not self.wait_otox_attrs(self.alice, 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: def wait_friend_get_connection_status(self, otox, fid:int, n:int = iN) -> int:
i = 0 i = 0
while i < n: while i < n:
i += 1
iRet = otox.friend_get_connection_status(fid) iRet = otox.friend_get_connection_status(fid)
if iRet == TOX_CONNECTION['NONE']: 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) self.loop_until_connected(otox)
else: else:
LOG.info(f"wait_friend_get_connection_status {iRet}") LOG.info(f"wait_friend_get_connection_status fid={fid} {iRet}")
return True return True
i += 1
else: 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 return False
def warn_if_no_cb(self, alice, sSlot:str) -> None: def warn_if_no_cb(self, alice, sSlot:str) -> None: