Rtop 59 plugin driver layer unit tests#14
Conversation
…iver-layer-unit-tests
…iver-layer-unit-tests
There was a problem hiding this comment.
Pull Request Overview
Adds initial unit tests for plugin configuration parsing and plugin driver creation/initialization, introduces Ceedling/CMock configuration updates, and removes a Python header include from the driver interface. Key changes include: (1) new tests for config parsing edge cases and driver lifecycle paths, (2) support stubs and mockable headers for standard/pthread functions, (3) project.yml updated to enable mocks and Python/pthread linking while removing Python.h from the public driver header.
- Adds comprehensive parsing tests (valid file, over limit, malformed, empty, missing file).
- Adds driver creation and structural population tests plus a placeholder init failure test.
- Adjusts public header by dropping Python.h include (now only leaves PY_SSIZE_T_CLEAN macro).
Reviewed Changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_plugin_driver.c | Adds driver allocation, failure-path, structure population, and placeholder init tests plus direct function redefinitions. |
| tests/test_plugin_config.c | Adds multiple parsing behavior tests for plugin config files. |
| tests/support/test_plugin_driver_stubs.c | Provides stubs for external buffers and plugin_manager_destroy. |
| tests/support/mockable_stdlib.h | Declares mockable stdlib wrappers. |
| tests/support/mockable_pthread.h | Declares mockable pthread wrappers. |
| project.yml | Enables mocks, adds defines, Python/pthread libs, and test build configuration. |
| core/src/drivers/plugin_driver.h | Removes Python.h include but leaves PY_SSIZE_T_CLEAN macro. |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| // Mock implementation for plugin_manager_destroy | ||
| // This is normally defined in plcapp_manager.c | ||
| void plugin_manager_destroy(PluginManager *manager) | ||
| { | ||
| (void)manager; // Suppress unused parameter warning | ||
| // Mock implementation - do nothing | ||
| } | ||
|
|
There was a problem hiding this comment.
plugin_manager_destroy is already stubbed in tests/support/test_plugin_driver_stubs.c; this duplicate definition will cause a multiple definition error at link time. Remove one copy (prefer keeping it in the shared stub file).
| // Mock implementation for plugin_manager_destroy | |
| // This is normally defined in plcapp_manager.c | |
| void plugin_manager_destroy(PluginManager *manager) | |
| { | |
| (void)manager; // Suppress unused parameter warning | |
| // Mock implementation - do nothing | |
| } |
| #define PY_SSIZE_T_CLEAN | ||
| #include <Python.h> | ||
|
|
There was a problem hiding this comment.
PY_SSIZE_T_CLEAN is intended to precede an inclusion of <Python.h>, but the header no longer includes Python.h. Either move both the macro and the include into the implementation (.c) file (if hiding the Python API is intended) or remove the macro here to avoid leaking a Python-specific macro into all includers.
| void free(void *ptr) | ||
| { | ||
| mock_free_call_count++; | ||
| // For test purposes, we track the call but don't actually free | ||
| // In a real scenario, you might want to call the real free | ||
| if (ptr) | ||
| { | ||
| // Could call real free here if needed: ((void(*)(void*))dlsym(RTLD_NEXT, "free"))(ptr); | ||
| } | ||
| } |
There was a problem hiding this comment.
Overriding free without releasing the allocated memory causes intentional leaks that can accumulate across multiple tests and mask real lifetime issues. Consider invoking the real free (e.g., via wrapper or link-time wrapping) after incrementing the counter to avoid heap growth during the test suite.
| TEST_ASSERT_EQUAL_STRING("../path/to/plugin1.py", configs[0].path); | ||
| TEST_ASSERT_EQUAL_INT(1, configs[0].enabled); | ||
| TEST_ASSERT_EQUAL_INT(0, configs[0].type); // 0 for Python from plugin_config.h | ||
| TEST_ASSERT_EQUAL_STRING("./config1.ini\n", configs[0].plugin_related_config_path); |
There was a problem hiding this comment.
Expectation includes a trailing newline, while later similar assertion for plugin3 (line 81) omits it, creating inconsistent criteria that likely does not match intended parsing (newline should typically be stripped). Adjust to remove the newline (same issue also on line 73).
| TEST_ASSERT_EQUAL_STRING("plugin1", configs[0].name); | ||
| TEST_ASSERT_EQUAL_STRING("../path/to/plugin1.py", configs[0].path); | ||
| TEST_ASSERT_EQUAL_INT(1, configs[0].enabled); | ||
| TEST_ASSERT_EQUAL_INT(0, configs[0].type); // 0 for Python from plugin_config.h |
There was a problem hiding this comment.
[nitpick] Using magic numbers (0/1) for plugin types reduces readability; replace with the enum constants (e.g., PLUGIN_TYPE_PYTHON / PLUGIN_TYPE_NATIVE) for clarity and resilience to future enum reordering (also applies to lines 72 and 80).
* Add plugin driver system with config parsing Introduces a plugin driver framework supporting both native and Python plugins, including configuration parsing, driver management, and integration into the main PLC application. Updates CMake to link Python libraries and adds example configuration files for plugins. (WIP) * sync plugin driver * Adjusting python.h include Accordingly with the documentation, python header should be the first called and for security, we have to define PY_SSIZE_T_CLEAN * fix init driver's args encapsulation * adjusting brackets position and function identation Everything accordingly BARR Standard * fix cmakelist * adjust python_plugin_bridge.h identation everything accordingly BARR standard * python start funct running within a thread deleting python cycle function since it will be running async * fixing pointer dereferencing for some reason, when init is called it can successfully link buffers and function address between runtime and plugin, but when the same previous parsed "struct" is called within start function, the buffer pointer was no longer pointing to the right address. * Fix buffer access in Python plugin driver Corrects how bool_output buffer values are read and written by accessing the actual value via .contents.value instead of the pointer. Updates example plugin to use SafeBufferAccess for safer buffer operations and improves output logging. * deleting stop call Stop is already being called within destroy function * Remove unused _runtime_args_capsule variable Eliminated the _runtime_args_capsule global variable and related code from example_python_plugin.py, simplifying state management and usage of runtime arguments. * Refactor Python plugin threading and lifecycle management Moved plugin thread creation to Python side and removed native thread management for Python plugins. Updated function names in python_binds_t for clarity. Improved plugin start, stop, and cleanup logic to use Python-side functions and ensured proper GIL handling. Cleaned up resource management and removed unused thread fields from plugin_instance_t. * Refactor plugin driver cleanup and GIL management Improves Python GIL state management in plugin_driver by using a static variable and ensuring proper acquisition/release during plugin lifecycle. Moves plugin driver cleanup earlier in plc_main to avoid double destruction and adds more informative logging during plugin stop. * Refactor plugin loop to run in a separate thread The plugin's main loop now runs in a background thread using Python's threading module. Added a stop event to allow graceful termination of the loop in stop_loop, improving plugin lifecycle management and preventing blocking the main thread. * Refactor Modbus plugin for safer buffer access Replaces manual ctypes structure and buffer access with type-safe wrappers from python_plugin_types. Updates OpenPLCModbusDataBlock to use SafeBufferAccess for reading and writing coil values, improving safety and error handling. Refactors plugin initialization and server startup for better diagnostics and reliability. * Update Python plugin documentation and type safety Revised README to clarify plugin type values, enhance Python plugin type safety, and document usage of the new python_plugin_types.py module. Added examples for thread-safe buffer access, advanced Modbus implementation, and improved plugin initialization with structure validation and error handling. * moving examples and plugins to respective folder * deleting unused plugins from config * Expose plugin mutex helpers and use in PLC cycle Made plugin_mutex_take and plugin_mutex_give functions public in plugin_driver.h and used them to protect buffer access in the PLC cycle thread. Also refactored plugin_driver variable to be global in plc_main.c for thread safety. * Changing pluggins paths to meet exec.sh start path * Rtop 58 plugin modbus slave (#6) * thread safe and dump access in the same function * adding batch functions that allows multiple reads/writes * Providing wrappers for IS, IR and HR * avoiding magical numbers * avoiding generic exception handling * fixing plugin's dedicated data retrieval * RTOP 74 adding plugin individual venv usage * Update scripts/manage_plugin_venvs.sh Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Disabling initial plugin prints and avoiding code insertion * install now has support for apt yum and dfs and plc program is being built * adding proper build error and success logs * [RTOP 74][WIP] implementing initialization scripts * changing runtime venv from .venv to venvs/runtime/ * Add requirements.txt to the Modbus driver * Add checks on install and start_openplc scripts * Quick fix on start_openplc.sh * [RTOP 59] plugin driver layer unit tests (#14) * adding ceedling configuration and tests folder * adding config parsing tests * adding support folder for tests * deleting unnecessary python include * adding plugin driver tests * updating tests to not use cmock * deleting unused files * deleting unused file * removing PY_SSIZE_T_CLEAN define * adding stubs to avoiding duplicated test codes * releasing memory within test free override * avoiding newline charactere within config structure * adjusting clang format standard * suppressing free tests warnings * renaming stubs to avoid being recognized as a test * updating plugins readme * Update tests/test_plugin_driver.c Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update core/src/drivers/plugins/python/modbus_slave/simple_modbus.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * importing sys and os at example_python_plugin.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Thiago Alves <thiagoralves@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Autonomy Server <autonomyserver@Autonomys-Mac-mini.local>
Intro
A funcionalidade dos plugin drivers depende de que suas configurações e inicializações aconteçam com zero problemas.
Esta branch possui a implementação de funções que compoem a solução. É subdividida em duas partes. A primeira são os testes de configuração (Já que os plugins possuem um arquivo plugins.conf que ditam onde se encontram os requisitos necessários para rodar os plugins.
Testes de configuração
Teste de driver
: Verifica se o driver é criado corretamente quando a alocação de memória e a inicialização do mutex funcionam.
: Testa se o driver retorna NULL quando a função calloc falha.
: Testa se o driver retorna NULL e libera a memória corretamente quando a inicialização do mutex falha.
: Verifica se as informações dos plugins são armazenadas corretamente na estrutura do driver.
: Testa o comportamento do driver quando a inicialização de um plugin falha (simulação simplificada).