From 7ce48e38f26ee7015a7c2c2f6229028796660283 Mon Sep 17 00:00:00 2001 From: dajiaohuang Date: Sat, 3 Oct 2026 07:13:52 +0800 Subject: [PATCH 1/2] Remove disconnected drawing board participants --- example/websensors/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/websensors/app.py b/example/websensors/app.py index 73f38c6..aa587ac 100644 --- a/example/websensors/app.py +++ b/example/websensors/app.py @@ -171,7 +171,7 @@ def unregister_participant(self, board_id, participant_id): """ if board_id in self.boards: board = self.boards[board_id] - if participant_id in self.boards[board_id]: + if participant_id in board['handlers']: board['handlers'].pop(participant_id, None) self.bus.log("Unregistering participant %s from board %s" % (participant_id, board_id)) From d6921d8d06f371940263a396633eb14d930b0273 Mon Sep 17 00:00:00 2001 From: dajiaohuang Date: Sun, 4 Oct 2026 19:55:00 +0800 Subject: [PATCH 2/2] Test drawing board participant removal and close callback --- requirements/py2kreqs.txt | 3 ++- requirements/py3kreqs.txt | 3 ++- test/test_drawingboard.py | 53 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 test/test_drawingboard.py diff --git a/requirements/py2kreqs.txt b/requirements/py2kreqs.txt index 30be8ff..0ed8bf6 100644 --- a/requirements/py2kreqs.txt +++ b/requirements/py2kreqs.txt @@ -1,7 +1,8 @@ CherryPy>=5.5.0 +Mako<1.2 tornado>=4.2.3 greenlet>=0.4.9 mock>=2.0.0 Cython>=0.22.1 gevent>=1.1.1 -pytest>=3.0.7 \ No newline at end of file +pytest>=3.0.7 diff --git a/requirements/py3kreqs.txt b/requirements/py3kreqs.txt index e8a6149..66dbdef 100644 --- a/requirements/py3kreqs.txt +++ b/requirements/py3kreqs.txt @@ -1,7 +1,8 @@ CherryPy>=5.5.0 +Mako tornado>=4.2.3 mock>=2.0.0 asyncio>=3.4.3 Cython>=0.22.1 gevent>=1.1.1 -pytest>=3.0.4 \ No newline at end of file +pytest>=3.0.4 diff --git a/test/test_drawingboard.py b/test/test_drawingboard.py new file mode 100644 index 0000000..1daaf59 --- /dev/null +++ b/test/test_drawingboard.py @@ -0,0 +1,53 @@ +import os +import sys +import unittest + +try: + from unittest.mock import patch +except ImportError: + from mock import patch + +import cherrypy +from cherrypy.process.wspbus import Bus + + +example_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), + 'example', 'websensors') +sys.path.insert(0, example_dir) +try: + with patch.object(cherrypy.tools, 'render', create=True), \ + patch.object(cherrypy.tools, 'websocket', create=True): + import app as drawingboard +finally: + sys.path.remove(example_dir) + + +class DrawingBoardTest(unittest.TestCase): + def setUp(self): + self.bus = Bus() + self.plugin = drawingboard.DrawingBoardWebSocketPlugin(self.bus) + self.bus.websockets = self.plugin + self.plugin.register_board('board') + self.alice = drawingboard.DrawingBoardWebSocketHandler(None) + self.bob = drawingboard.DrawingBoardWebSocketHandler(None) + self.plugin.register_participant('board', 'alice', self.alice) + self.plugin.register_participant('board', 'bob', self.bob) + + def test_unregister_participant_preserves_other_handlers(self): + self.plugin.unregister_participant('board', 'alice') + self.assertEqual(self.plugin.boards['board']['handlers'], + {'bob': self.bob}) + + def test_closed_callback_unregisters_participant(self): + with patch.object(drawingboard, 'bus', self.bus): + self.alice.closed(1000, 'done') + self.assertEqual(self.plugin.boards['board']['handlers'], + {'bob': self.bob}) + + def test_unknown_and_repeated_unregistration_are_harmless(self): + self.plugin.unregister_participant('board', 'alice') + self.plugin.unregister_participant('board', 'alice') + self.plugin.unregister_participant('board', 'unknown') + self.plugin.unregister_participant('unknown', 'bob') + self.assertEqual(self.plugin.boards['board']['handlers'], + {'bob': self.bob})