From 9703a96afcced70dac20657da54a61cc29c4dc13 Mon Sep 17 00:00:00 2001 From: Benjamin Braatz Date: Sat, 20 Mar 2021 21:53:49 +0100 Subject: [PATCH] Add tests for __init__.py. --- controlpi/__init__.py | 61 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/controlpi/__init__.py b/controlpi/__init__.py index cc40432..173af72 100644 --- a/controlpi/__init__.py +++ b/controlpi/__init__.py @@ -2,9 +2,13 @@ The infrastructure consists of the message bus from module messagebus, the plugin registry from module pluginregistry and the abstract base plugin from -the module baseplugin. +module baseplugin. -The package combines them in its run function. +The package combines them in its run function, which is used by __main__.py +to run a ControlPi system based on a configuration file indefinitely. + +The test function is a utility function to test plugins with minimal +boilerplate code. """ import asyncio import jsonschema # type: ignore @@ -15,6 +19,7 @@ from controlpi.baseplugin import BasePlugin, PluginConf, ConfException from typing import Dict, List, Coroutine, Any + CONF_SCHEMA = {'type': 'object', 'patternProperties': {'.*': {'type': 'object'}}} @@ -58,7 +63,27 @@ async def run(conf: Dict[str, PluginConf]) -> None: Setup message bus, process given configuration, and run message bus and plugins concurrently and indefinitely. - TODO: doctests for run using util.py + This function is mainly used by __main__.py to run a ControlPi system + based on a configuration loaded from a configuration JSON file on disk. + + >>> async def test_coroutine(): + ... conf = {"Example Init": + ... {"plugin": "Init", + ... "messages": [{"id": 42, + ... "content": "Test Message"}, + ... {"id": 42.42, + ... "content": "Second Message"}]}, + ... "Example Log": + ... {"plugin": "Log", + ... "filter": [{"sender": {"const": "Example Init"}}]}} + ... run_task = asyncio.create_task(run(conf)) + ... await asyncio.sleep(0.1) + ... run_task.cancel() + >>> asyncio.run(test_coroutine()) # doctest: +NORMALIZE_WHITESPACE + Example Log: {'sender': 'Example Init', + 'id': 42, 'content': 'Test Message'} + Example Log: {'sender': 'Example Init', + 'id': 42.42, 'content': 'Second Message'} """ message_bus = MessageBus() coroutines = _process_conf(message_bus, conf) @@ -76,6 +101,8 @@ async def test(conf: Dict[str, PluginConf], plugins concurrently, send given messages on message bus and print all messages on message bus. Terminate when queue of message bus is empty. + This function allows to test single plugins or small plugin + configurations with minimal boilerplate code: >>> asyncio.run(test( ... {"Example Init": {"plugin": "Init", ... "messages": [{"id": 42, @@ -89,23 +116,37 @@ async def test(conf: Dict[str, PluginConf], 'sends': [{'id': {'const': 42}, 'content': {'const': 'Test Message'}}, {'id': {'const': 42.42}, - 'content': {'const': 'Second Message'}}, - {'target': {'const': 'Example Init'}, - 'command': {'const': 'execute'}}], + 'content': {'const': 'Second Message'}}], 'receives': [{'target': {'const': 'Example Init'}, 'command': {'const': 'execute'}}]} - test(): {'sender': 'Example Init', 'target': 'Example Init', - 'command': 'execute'} - test(): {'sender': 'test()', 'target': 'Example Init', - 'command': 'execute'} test(): {'sender': 'Example Init', 'id': 42, 'content': 'Test Message'} test(): {'sender': 'Example Init', 'id': 42.42, 'content': 'Second Message'} + test(): {'sender': 'test()', 'target': 'Example Init', + 'command': 'execute'} test(): {'sender': 'Example Init', 'id': 42, 'content': 'Test Message'} test(): {'sender': 'Example Init', 'id': 42.42, 'content': 'Second Message'} + + Similar functionality could be reached by using the Log and Init plugins + to print messages and send some messages on the bus, but these would + clutter the test configuration and code to stop the idefinitely running + bus would have to be added to each and every test. + + Incorrect plugin configurations can also be tested by this: + >>> asyncio.run(test( + ... {"Example Init": {"plugin": "Init"}}, [])) + 'messages' is a required property + + Failed validating 'required' in schema: + {'properties': {'messages': {'type': 'array'}}, + 'required': ['messages']} + + On instance: + {'plugin': 'Init'} + Configuration for 'Example Init' is not valid. """ message_bus = MessageBus() -- 2.34.1