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:
parent
2bbda63b9c
commit
daf556ca50
|
@ -367,10 +367,11 @@ class Main:
|
|||
time.time() - state.last_api_response >= 30):
|
||||
self.stop()
|
||||
elif not state.enableGUI:
|
||||
from tests import core
|
||||
test_core_result = core.run()
|
||||
from tests import core as test_core
|
||||
test_core_result = test_core.run()
|
||||
state.enableGUI = True
|
||||
self.stop()
|
||||
test_core.cleanup()
|
||||
sys.exit(
|
||||
'Core tests failed!'
|
||||
if test_core_result.errors or test_core_result.failures
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import threading
|
||||
|
||||
from bmconfigparser import BMConfigParser
|
||||
import network.asyncore_pollchoose as asyncore
|
||||
import state
|
||||
from debug import logger
|
||||
from helper_threading import StoppableThread
|
||||
import network.asyncore_pollchoose as asyncore
|
||||
from network.connectionpool import BMConnectionPool
|
||||
import state
|
||||
from queues import excQueue
|
||||
|
||||
|
||||
class BMNetworkThread(threading.Thread, StoppableThread):
|
||||
def __init__(self):
|
||||
|
@ -15,8 +16,12 @@ class BMNetworkThread(threading.Thread, StoppableThread):
|
|||
logger.info("init asyncore thread")
|
||||
|
||||
def run(self):
|
||||
while not self._stopped and state.shutdown == 0:
|
||||
BMConnectionPool().loop()
|
||||
try:
|
||||
while not self._stopped and state.shutdown == 0:
|
||||
BMConnectionPool().loop()
|
||||
except Exception as e:
|
||||
excQueue.put((self.name, e))
|
||||
raise
|
||||
|
||||
def stopThread(self):
|
||||
super(BMNetworkThread, self).stopThread()
|
||||
|
|
|
@ -6,11 +6,15 @@ from multiqueue import MultiQueue
|
|||
workerQueue = Queue.Queue()
|
||||
UISignalQueue = 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()
|
||||
invQueue = MultiQueue()
|
||||
addrQueue = MultiQueue()
|
||||
portCheckerQueue = Queue.Queue()
|
||||
receiveDataQueue = Queue.Queue()
|
||||
apiAddressGeneratorReturnQueue = Queue.Queue(
|
||||
) # The address generator thread uses this queue to get information back to the API thread.
|
||||
# The address generator thread uses this queue to get information back
|
||||
# to the API thread.
|
||||
apiAddressGeneratorReturnQueue = Queue.Queue()
|
||||
# Exceptions
|
||||
excQueue = Queue.Queue()
|
||||
|
|
|
@ -3,11 +3,39 @@ Tests for core and those that do not work outside
|
|||
(because of import error for example)
|
||||
"""
|
||||
|
||||
import os
|
||||
import pickle # nosec
|
||||
import Queue
|
||||
import random # nosec
|
||||
import string
|
||||
import time
|
||||
import unittest
|
||||
|
||||
import knownnodes
|
||||
import state
|
||||
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):
|
||||
|
@ -42,8 +70,48 @@ class TestCore(unittest.TestCase):
|
|||
self.assertEqual(msg_data['subject'], obj3e.subject)
|
||||
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():
|
||||
"""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)
|
||||
|
|
Reference in New Issue
Block a user