fix sloppy Server event loop management, add Server tests

This commit is contained in:
2024-04-28 14:35:04 -07:00
parent f1e0b5602b
commit 24bb04ec5c
11 changed files with 390 additions and 45 deletions

View File

@@ -0,0 +1 @@
test text

View File

@@ -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}")

View File

@@ -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

View File

@@ -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

View File

@@ -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']