.. tutorial_tests:
***********************
How To: Test in EVerest
***********************
This is a tutorial on how to setup your test environment for EVerest.
Requirements
============
A successful build of *everest-core* is required. Refer to
`everest-core `_ for this.
Some test cases require the installation of *everestpy*.
You can do this after a successful build of *everest-core*:
.. code-block:: bash
cd everest-core
cmake --build build --target everestpy_pip_install_dist
Sometimes the ``everstpy`` module might require manual installation.
That can be done by running:
.. code-block:: bash
cd everest-framework/everestpy
python3 -m pip install .
Install the python package containing the EVerest test utilities from
`everest-testing `_.
Install the requirements of this repository:
.. code-block:: bash
python3 -m pip install -r requirements.txt
Some test cases require the installation of *Josev*.
This should be located in your EVerest workspace:
.. code-block:: bash
cd
python3 -m pip install -r requirements.txt
python3 -m pip install .
For most test cases you need a correct setup of certificates and configs within
EVerest. You can use
.. code-block:: bash
cd test_sets/ocpp_tests/everest_aux
./install_certs.sh
./install_configs.sh
to install the certificates within *everest-aux* into the correct location of
*everest-core*.
An MQTT server is needed for testing.
Docker can be used for this.
Refer to
`docker-setup `_
for this.
Test sets
=========
Run any test set (e.g. ocpp_compliance_tests.py) with:
.. code-block:: bash
python3 -m pytest test_sets/ocpp_tests/ocpp16/ocpp_compliance_tests.py --everest-prefix /build/dist --libocpp
or run a single test case with:
.. code-block:: bash
python3 -m pytest test_sets/ocpp_tests/ocpp16/ocpp_compliance_tests.py --everest-prefix /build/dist/ --libocpp -k 'test_remote_start_first' -s
or run all tests in parallel with:
.. code-block:: bash
./run-testing.sh
If running from the ``everest-core/tests/ocpp_tests`` directory, the path to
*everest-core* or *libocpp* can be relative, for example:
.. code-block:: bash
--everest-prefix ../../../everest-core/build/dist --libocpp ../../../libocpp/
.. note::
Here is a TODO: We have to update the documentation for known failing
tests.
View OCPP test logs
===================
While running the tests, EVerest logs OCPP message to its log directory.
These logs are stored in HTML files.
When you open the following directory in your web browser you can view to logs:
.. code-block:: bash
/tmp/everest_ocpp_test_logs/
VS Code Debugging
=================
Debugging can have various layers depending on the feature tested.
This part will focus on debugging inside VS Code.
Python debugging
----------------
Tests can be manually launched by adding the proper entries to the
'launch.json' file.
Example for debugging a test from ``ocpp_compliance_tests.py``:
.. code-block:: json
"configurations": [
{
"name": "Python: OCPP Compliance Test",
"type": "debugpy",
"request": "launch",
"module": "pytest",
"args": [
"test_sets/ocpp_tests/ocpp16/ocpp_compliance_tests.py",
"--libocpp", "../libocpp/",
"--everest-prefix", "../everest-core/build/dist",
"-s", "-vv", "-k", "your_test_here",
],
"cwd": "${workspaceFolder}/ocpp-testing/",
"console": "integratedTerminal",
"justMyCode":false
}
]
The paths can differ based on the workspace setup.
.. tutorial_tests_cpp_debug_attach:
C++ debugging
-------------
When a certain test case executes, there is a chance that C++ code can be
faulty, requiring a GDB attach in order to detect an issue.
In that case, the following steps can be followed:
- setup for python debugging
- setup for c++ debugging with the following config entry:
.. code-block:: json
"configurations": [
{
"name": "(gdb) Attach PID",
"type": "cppdbg",
"request": "attach",
"program": "${workspaceFolder}/everest-core/build/dist/bin/manager",
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Set Disassembly Flavor to Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
]
}
]
- build *everest-core* with debugging enabled: ``cmake .. -DCMAKE_BUILD_TYPE=Debug``
- run the desired test from python debugging (```Python: OCPP Compliance Test```) and place a breakpoint near the test's entry point
- copy the PID from the variable 'test_controller: TestController' from the test's function: ``test_controller->_everest_core->process->pid``
- run ```pstree -pT ${pid}``` with the retrieved pid for example 102590:
.. code-block:: bash
pstree -pT 102590
manager(102590)─┬─auth:Auth(102653)
├─car_simulator:J(102654)
├─connector_1:Evs(102655)
├─controller(102595)
├─energy_manager:(102656)
├─evse_security:E(102657)
├─grid_connection(102658)
├─ocpp:OCPP(102660)
├─python3(102659)
├─slac:JsSlacSimu(102661)
├─system:System(102662)
├─token_provider_(102663)
└─yeti_driver:JsY(102664)
- while the test is in the breakpoint, run the `(gdb) Attach PID` configuration with the desired module to attach to
- in the VS code terminal prompt input 'y' and insert the root password
- unpause the python `Python: OCPP Compliance Test` debug session
External integration
====================
The main motive for external integration is the flexibility of running
EVerest outside of the SIL environment.
Therefore, the *ocpp-tests* can be run with any out-of-tree versions of
EVerest.
Currently, there are different versions of EVerest that should be able to run
*ocpp-tests*:
- SIL
- BaseCamp
The ``test_sets`` folder can be embedded in any external repository that uses
EVerest.
The external EVerest does not have to include all the components required by
the SIL version.
Due to the limitations of *pytest*, the
`conftest.py `_
file must not be included, in order to preserve the needs of the external project.
In order to use the proper fixtures for the ``[test_sets](test_sets)`` inside an
external repository, a custom `conftest.py` specific for that project has to
provide all the necessary fixtures for running the tests.
Example fixture
---------------
The `test_F01_F02_F03`` requires the following fixtures:
.. code-block:: python
async def test_F01_F02_F03(charge_point_v201: ChargePoint201, test_controller: TestController, test_utility: TestUtility):
The project-specific `conftest.py` must provide the proper fixtures that are
custom for the project - in our case the `test_controller` fixture:
.. code-block:: python
# Add necessary handling in here
class ExternalTestControllerAdapter(TestController):
def __init__(self):
pass
def start_thread(self):
pass
def stop_thread(self):
pass
def start(self):
pass
def stop(self):
pass
def plug_in(self, connector_id=1):
pass
def plug_in_ac_iso(self, payment_type, connector_id):
raise NotImplementedError()
def plug_out(self, connector_id=1):
pass
async def swipe_async(self, token):
pass
@pytest.fixture
def test_controller(everest_core: EverestCore):
controller = ExternalTestControllerAdapter(
everest_core
)
controller.start()
yield controller
controller.stop()
Example marker injection
------------------------
Sometimes the tests do not have all the required
`pytest markers `_.
The test ``test_F01_F02_F03`` might require additional markers in the context
of an external repo.
That can be achieved at runtime using
`pytest hooks `_.
For example if the test might require the
.. code-block:: python
pytest.mark.use_temporary_persistent_store
pytest.mark.ocpp_config(Path("path-to-config"))
markers that are not present in the test header.
They can be injected by adding the following code to the `conftest.py` of the
specific external project:
.. code-block:: python
def pytest_collection_modifyitems(session, config, items):
marks = (
pytest.mark.use_temporary_persistent_store,
pytest.mark.ocpp_config(Path("path-to-config"))
)
for item in items:
if "ocpp_testing" in item.path.as_posix():
for marker in marks:
item.add_marker(marker)
pass
The result is that before running each selected test under ``test_sets``, the
markers will be applied, modifying the default behavior of the tests.
Required mocks
==============
In order to properly run the tests, certain mocks have to be implemented.
Different versions of EVerest might require different mock implementations,
that might include but not be limited to:
- charge_point_v16
- charge_point_v201
- test_controller
- ocpp_test_mocks
- test_utility