fix sloppy Server event loop management, add Server tests
This commit is contained in:
1
tests/endpoint_proxy/fileB
Normal file
1
tests/endpoint_proxy/fileB
Normal file
@@ -0,0 +1 @@
|
||||
test text
|
||||
@@ -0,0 +1,7 @@
|
||||
# from websockets.sync.client import connect
|
||||
#
|
||||
# def hello():
|
||||
# with connect("ws://localhost:8765") as websocket:
|
||||
# websocket.send("Hello world!")
|
||||
# message = websocket.recv()
|
||||
# print(f"Received: {message}")
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
import time
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from functools import partial
|
||||
|
||||
from execlog import util
|
||||
from execlog import ChainRouter, Event
|
||||
from execlog.routers import PathRouter
|
||||
from execlog.listeners import PathListener
|
||||
|
||||
|
||||
logger = logging.getLogger()
|
||||
logger.setLevel(logging.DEBUG)
|
||||
logger.addHandler(util.generic.TqdmLoggingHandler())
|
||||
|
||||
# router setup
|
||||
router1 = PathRouter()
|
||||
router2 = PathRouter()
|
||||
router3 = PathRouter()
|
||||
|
||||
chain_router = ChainRouter([router1, router2, router3])
|
||||
|
||||
# router-1
|
||||
router1.register('tests/endpoint_proxy', partial(print, 'R1-1 ::'))
|
||||
|
||||
# router-2
|
||||
router2.register('tests/endpoint_proxy', partial(print, 'R2-1 ::'))
|
||||
router2.register('tests/endpoint_proxy', partial(print, 'R2-2 ::'))
|
||||
|
||||
# router-3
|
||||
router3.register('tests/endpoint_proxy', partial(print, 'R3-1 ::'))
|
||||
router3.register('tests/endpoint_proxy', partial(print, 'R3-2 ::'))
|
||||
router3.register('tests/endpoint_proxy', partial(print, 'R3-3 ::'))
|
||||
|
||||
|
||||
def test_single_path_listener():
|
||||
'''
|
||||
1. Get listener for a single router
|
||||
2. Start listening for file events
|
||||
3. Create a few files under the registered path
|
||||
4. Wait a second for inotify to pick up on the events, allow jobs to be submitted to
|
||||
the router's thread pool
|
||||
5. Shutdown the listener; any lingering jobs will be finished if not done already
|
||||
'''
|
||||
listener = router1.get_listener()
|
||||
|
||||
# listener starts in new thread
|
||||
listener.start()
|
||||
|
||||
file_a = Path('tests/endpoint_proxy/fileA')
|
||||
file_a.write_text('test text')
|
||||
file_a.unlink()
|
||||
|
||||
file_b = Path('tests/endpoint_proxy/fileB')
|
||||
file_b.write_text('test text')
|
||||
|
||||
# allow I/O to propagate
|
||||
time.sleep(1)
|
||||
|
||||
listener.stop()
|
||||
|
||||
assert True
|
||||
|
||||
def test_chain_path_listener():
|
||||
listener = chain_router.get_listener()
|
||||
|
||||
# listener starts in new thread
|
||||
listener.start()
|
||||
|
||||
file_a = Path('tests/endpoint_proxy/fileA')
|
||||
file_a.write_text('test text')
|
||||
file_a.unlink()
|
||||
|
||||
file_b = Path('tests/endpoint_proxy/fileB')
|
||||
file_b.write_text('test text')
|
||||
|
||||
# allow I/O to propagate
|
||||
time.sleep(1)
|
||||
|
||||
listener.stop()
|
||||
|
||||
assert True
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from functools import partial
|
||||
|
||||
from execlog import util
|
||||
from execlog import ChainRouter, Event
|
||||
from execlog.routers import PathRouter
|
||||
from execlog.listeners import PathListener
|
||||
|
||||
|
||||
logger = logging.getLogger()
|
||||
logger.setLevel(logging.DEBUG)
|
||||
logger.addHandler(util.generic.TqdmLoggingHandler())
|
||||
|
||||
# router setup
|
||||
router1 = PathRouter()
|
||||
router2 = PathRouter()
|
||||
router3 = PathRouter()
|
||||
|
||||
chain_router = ChainRouter([router1, router2, router3])
|
||||
|
||||
def test_route_registry():
|
||||
# router-1
|
||||
router1.register('endpoint_proxy', partial(print, 'R1-1 ::'))
|
||||
|
||||
# router-2
|
||||
router2.register('endpoint_proxy', partial(print, 'R2-1 ::'))
|
||||
router2.register('endpoint_proxy', partial(print, 'R2-2 ::'))
|
||||
|
||||
# router-3
|
||||
router3.register('endpoint_proxy', partial(print, 'R3-1 ::'))
|
||||
router3.register('endpoint_proxy', partial(print, 'R3-2 ::'))
|
||||
router3.register('endpoint_proxy', partial(print, 'R3-3 ::'))
|
||||
|
||||
assert True
|
||||
|
||||
def test_single_router_submission():
|
||||
events = [
|
||||
Event(endpoint='endpoint_proxy', name='file1'),
|
||||
Event(endpoint='endpoint_proxy', name='file2'),
|
||||
Event(endpoint='endpoint_proxy', name='file3'),
|
||||
]
|
||||
futures = router2.submit(events)
|
||||
router2.wait_on_futures(futures)
|
||||
|
||||
assert True
|
||||
|
||||
def test_chain_router_submission():
|
||||
events = [
|
||||
Event(endpoint='endpoint_proxy', name='file1'),
|
||||
Event(endpoint='endpoint_proxy', name='file2'),
|
||||
Event(endpoint='endpoint_proxy', name='file3'),
|
||||
]
|
||||
futures = chain_router.submit(events)
|
||||
chain_router.wait_on_futures(futures)
|
||||
|
||||
assert True
|
||||
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
import time
|
||||
import multiprocessing as mp
|
||||
import threading
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
from execlog import Server
|
||||
from execlog.routers import PathRouter
|
||||
|
||||
|
||||
logger = logging.getLogger()
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
def threaded_start_then_join(server):
|
||||
thread = threading.Thread(target=server.start)
|
||||
|
||||
# start the server; is a blocking call in that thread
|
||||
thread.start()
|
||||
|
||||
# short wait here in main thread for some startup procedures
|
||||
time.sleep(1)
|
||||
|
||||
# call shutdown from this thread
|
||||
server.shutdown()
|
||||
|
||||
# join the thread back to main thread; if successfully started but shutdown failed,
|
||||
# joining back would cause indefinite blockage
|
||||
thread.join()
|
||||
|
||||
# doesn't appear to be a more formal way to check if server is officially running;
|
||||
# done a lot of digging here. No flags, state; I imagine it's actually difficult to
|
||||
# know if the process is actually stopped. In any case, the above logic is good enough
|
||||
# for my use case as far as I'm concerned.
|
||||
return True
|
||||
|
||||
|
||||
def test_server_creation():
|
||||
server = Server(
|
||||
host='localhost',
|
||||
port=8778,
|
||||
root='.'
|
||||
)
|
||||
|
||||
assert threaded_start_then_join(server)
|
||||
|
||||
def test_server_static():
|
||||
server = Server(
|
||||
host='localhost',
|
||||
port=8778,
|
||||
root='.',
|
||||
static=True
|
||||
)
|
||||
|
||||
assert threaded_start_then_join(server)
|
||||
|
||||
def test_server_livereload():
|
||||
server = Server(
|
||||
host='localhost',
|
||||
port=8778,
|
||||
root='.',
|
||||
livereload=True,
|
||||
)
|
||||
|
||||
assert threaded_start_then_join(server)
|
||||
|
||||
def test_server_with_listeners():
|
||||
router1 = PathRouter()
|
||||
router1.register('tests/endpoint_proxy', lambda _: 'router1 job success')
|
||||
|
||||
router2 = PathRouter()
|
||||
router2.register('tests/endpoint_proxy', lambda _: 'router2 job success')
|
||||
|
||||
listeners = [router1.get_listener(), router2.get_listener()]
|
||||
|
||||
server = Server(
|
||||
host='localhost',
|
||||
port=8778,
|
||||
root='.',
|
||||
managed_listeners=listeners,
|
||||
)
|
||||
thread = threading.Thread(target=server.start)
|
||||
thread.start()
|
||||
|
||||
# write a file to a registered endpoint
|
||||
file_a = Path('tests/endpoint_proxy/server_file')
|
||||
file_a.write_text('test text')
|
||||
file_a.unlink()
|
||||
|
||||
# wait a sec
|
||||
time.sleep(2)
|
||||
|
||||
# attempt to shutdown the server, join the thread back
|
||||
# successful if not blocking
|
||||
server.shutdown()
|
||||
thread.join()
|
||||
|
||||
# finally check the router event logs
|
||||
assert router1.event_log[0][1] == ['router1 job success']
|
||||
assert router2.event_log[0][1] == ['router2 job success']
|
||||
|
||||
|
||||
Reference in New Issue
Block a user