Added tests for knownnodes:

- import of pickled knownnodes;
  - default knownnodes if nothing imported;
  - knownnodes starvation (#1335), demanded changes in networkthread.
This commit is contained in:
Dmitri Bogomolov 2018-10-03 18:42:12 +03:00
parent 2bbda63b9c
commit daf556ca50
Signed by untrusted user: g1itch
GPG Key ID: 720A756F18DEED13
4 changed files with 89 additions and 11 deletions

View File

@ -367,10 +367,11 @@ class Main:
time.time() - state.last_api_response >= 30): time.time() - state.last_api_response >= 30):
self.stop() self.stop()
elif not state.enableGUI: elif not state.enableGUI:
from tests import core from tests import core as test_core
test_core_result = core.run() test_core_result = test_core.run()
state.enableGUI = True state.enableGUI = True
self.stop() self.stop()
test_core.cleanup()
sys.exit( sys.exit(
'Core tests failed!' 'Core tests failed!'
if test_core_result.errors or test_core_result.failures if test_core_result.errors or test_core_result.failures

View File

@ -1,11 +1,12 @@
import threading import threading
from bmconfigparser import BMConfigParser import network.asyncore_pollchoose as asyncore
import state
from debug import logger from debug import logger
from helper_threading import StoppableThread from helper_threading import StoppableThread
import network.asyncore_pollchoose as asyncore
from network.connectionpool import BMConnectionPool from network.connectionpool import BMConnectionPool
import state from queues import excQueue
class BMNetworkThread(threading.Thread, StoppableThread): class BMNetworkThread(threading.Thread, StoppableThread):
def __init__(self): def __init__(self):
@ -15,8 +16,12 @@ class BMNetworkThread(threading.Thread, StoppableThread):
logger.info("init asyncore thread") logger.info("init asyncore thread")
def run(self): def run(self):
try:
while not self._stopped and state.shutdown == 0: while not self._stopped and state.shutdown == 0:
BMConnectionPool().loop() BMConnectionPool().loop()
except Exception as e:
excQueue.put((self.name, e))
raise
def stopThread(self): def stopThread(self):
super(BMNetworkThread, self).stopThread() super(BMNetworkThread, self).stopThread()

View File

@ -6,11 +6,15 @@ from multiqueue import MultiQueue
workerQueue = Queue.Queue() workerQueue = Queue.Queue()
UISignalQueue = Queue.Queue() UISignalQueue = Queue.Queue()
addressGeneratorQueue = Queue.Queue() addressGeneratorQueue = Queue.Queue()
# receiveDataThreads dump objects they hear on the network into this queue to be processed. # receiveDataThreads dump objects they hear on the network into this
# queue to be processed.
objectProcessorQueue = ObjectProcessorQueue() objectProcessorQueue = ObjectProcessorQueue()
invQueue = MultiQueue() invQueue = MultiQueue()
addrQueue = MultiQueue() addrQueue = MultiQueue()
portCheckerQueue = Queue.Queue() portCheckerQueue = Queue.Queue()
receiveDataQueue = Queue.Queue() receiveDataQueue = Queue.Queue()
apiAddressGeneratorReturnQueue = Queue.Queue( # The address generator thread uses this queue to get information back
) # The address generator thread uses this queue to get information back to the API thread. # to the API thread.
apiAddressGeneratorReturnQueue = Queue.Queue()
# Exceptions
excQueue = Queue.Queue()

View File

@ -3,11 +3,39 @@ Tests for core and those that do not work outside
(because of import error for example) (because of import error for example)
""" """
import os
import pickle # nosec
import Queue
import random # nosec import random # nosec
import string import string
import time
import unittest import unittest
import knownnodes
import state
from helper_msgcoding import MsgEncode, MsgDecode from helper_msgcoding import MsgEncode, MsgDecode
from queues import excQueue
knownnodes_file = os.path.join(state.appdata, 'knownnodes.dat')
def pickle_knownnodes():
now = time.time()
with open(knownnodes_file, 'wb') as dst:
pickle.dump({
stream: {
state.Peer(
'%i.%i.%i.%i' % tuple([
random.randint(1, 255) for i in range(4)]),
8444): {'lastseen': now, 'rating': 0.1}
for i in range(1, 4) # 3 test nodes
}
for stream in range(1, 4) # 3 test streams
}, dst)
def cleanup():
os.remove(knownnodes_file)
class TestCore(unittest.TestCase): class TestCore(unittest.TestCase):
@ -42,8 +70,48 @@ class TestCore(unittest.TestCase):
self.assertEqual(msg_data['subject'], obj3e.subject) self.assertEqual(msg_data['subject'], obj3e.subject)
self.assertEqual(msg_data['body'], obj3e.body) self.assertEqual(msg_data['body'], obj3e.body)
def _wipe_knownnodes(self):
with knownnodes.knownNodesLock:
knownnodes.knownNodes = {stream: {} for stream in range(1, 4)}
def test_knownnodes_pickle(self):
"""ensure that 3 nodes was imported for each stream"""
pickle_knownnodes()
self._wipe_knownnodes()
knownnodes.readKnownNodes()
for nodes in knownnodes.knownNodes.itervalues():
self_count = n = 0
for n, node in enumerate(nodes.itervalues()):
if node.get('self'):
self_count += 1
self.assertEqual(n - self_count, 2)
def test_knownnodes_default(self):
"""test adding default knownnodes if nothing loaded"""
cleanup()
self._wipe_knownnodes()
knownnodes.readKnownNodes()
self.assertGreaterEqual(
len(knownnodes.knownNodes[1]), len(knownnodes.DEFAULT_NODES))
def test_0_cleaner(self):
"""test knownnodes starvation leading to IndexError in Asyncore"""
for nodes in knownnodes.knownNodes.itervalues():
for node in nodes.itervalues():
node['lastseen'] -= 2419205 # older than 28 days
time.sleep(303) # singleCleaner wakes up every 5 min
while True:
try:
thread, exc = excQueue.get(block=False)
except Queue.Empty:
return
if thread == 'Asyncore' and isinstance(exc, IndexError):
self.fail("IndexError because of empty knownNodes!")
def run(): def run():
"""Starts all tests defined in this module""" """Starts all tests defined in this module"""
suite = unittest.TestLoader().loadTestsFromTestCase(TestCore) loader = unittest.TestLoader()
loader.sortTestMethodsUsing = None
suite = loader.loadTestsFromTestCase(TestCore)
return unittest.TextTestRunner(verbosity=2).run(suite) return unittest.TextTestRunner(verbosity=2).run(suite)