Files
Eric F d398a6ced2 Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter
- CitrineOS core extracted (CSMS OCPP 2.0.1)
- OpenOCPP extracted (firmware OCPP 1.6J/2.0.1)
- ShapeShifter library installed (pip install -e)
- ShapeShifter specification extracted
- EVerest extracted

TODO updated with progress
2026-06-08 00:38:27 -04:00

156 lines
5.3 KiB
Python

# SPDX-License-Identifier: Apache-2.0
# Copyright Pionix GmbH and Contributors to EVerest
import json
import pytest
from everest.testing.core_utils.controller.test_controller_interface import (
TestController,
)
from ocpp.v201.datatypes import SetVariableDataType, VariableType, ComponentType
from ocpp.v201 import call as call201
from ocpp.messages import Call, _DecimalEncoder
from ocpp.charge_point import asdict, remove_nones, snake_to_camel_case
# fmt: off
from everest.testing.ocpp_utils.charge_point_utils import TestUtility
from everest_test_utils import get_everest_config_path_str, send_message_without_validation
from everest.testing.ocpp_utils.central_system import CentralSystem
from everest.testing.ocpp_utils.charge_point_v201 import ChargePoint201
from validations import wait_for_callerror_and_validate
# fmt: on
@pytest.mark.asyncio
@pytest.mark.ocpp_version("ocpp2.0.1")
@pytest.mark.everest_core_config(
get_everest_config_path_str("everest-config-ocpp201.yaml")
)
async def test_invalid_payloads(
central_system_v201: CentralSystem,
charge_point_v201: ChargePoint201,
test_controller: TestController,
test_utility: TestUtility,
):
# a payload field that is too long should trigger a FormationViolation CALLERROR
too_long_component_type_name_payload = call201.SetVariables(
set_variable_data=[SetVariableDataType(attribute_value="abc", component=ComponentType(
name="ThisIsMuchLongerThan50charactersThisIsMuchLongerThan50charactersThisIsMuchLongerThan50charactersThisIsMuchLongerThan50charactersThisIsMuchLongerThan50characters"), variable=VariableType(name="VariableName"))]
)
camel_case_payload = snake_to_camel_case(
asdict(too_long_component_type_name_payload))
call_msg = Call(
unique_id=str(charge_point_v201._unique_id_generator()),
action=too_long_component_type_name_payload.__class__.__name__,
payload=remove_nones(camel_case_payload),
)
await send_message_without_validation(charge_point_v201, call_msg)
assert await wait_for_callerror_and_validate(
test_utility, charge_point_v201, "FormationViolation"
)
# a unknown action should trigger a FormationViolation CALLERROR
call_msg = Call(
unique_id=str(charge_point_v201._unique_id_generator()),
action="ThisIsAnUnknownAction",
payload="Invalid",
)
await send_message_without_validation(charge_point_v201, call_msg)
assert await wait_for_callerror_and_validate(
test_utility, charge_point_v201, "FormationViolation"
)
# a malformed CALL should trigger a RpcFrameworkError CALLERROR
call_msg = "{Malformed"
async with charge_point_v201._call_lock:
await charge_point_v201._send(call_msg)
assert await wait_for_callerror_and_validate(
test_utility, charge_point_v201, "RpcFrameworkError"
)
# a malformed CALL should trigger a RpcFrameworkError CALLERROR
call_msg = b"\xd8\x00\x00\x00"
async with charge_point_v201._call_lock:
await charge_point_v201._send(call_msg)
assert await wait_for_callerror_and_validate(
test_utility, charge_point_v201, "RpcFrameworkError"
)
# a invalid payload should trigger a FormationViolation CALLERROR
call_msg = Call(
unique_id=str(charge_point_v201._unique_id_generator()),
action="SetVariables",
payload=None,
)
await send_message_without_validation(charge_point_v201, call_msg)
assert await wait_for_callerror_and_validate(
test_utility, charge_point_v201, "FormationViolation"
)
# a CALL message without UUID, action and payload should trigger a RpcFrameworkError CALLERROR
json_data = json.dumps(
[
2, # CALL
],
# By default json.dumps() adds a white space after every separator.
# By setting the separator manually that can be avoided.
separators=(",", ":"),
cls=_DecimalEncoder,
)
async with charge_point_v201._call_lock:
await charge_point_v201._send(json_data)
assert await wait_for_callerror_and_validate(
test_utility, charge_point_v201, "RpcFrameworkError"
)
# a completely empty message should trigger a RpcFrameworkError CALLERROR
json_data = json.dumps(
[
],
# By default json.dumps() adds a white space after every separator.
# By setting the separator manually that can be avoided.
separators=(",", ":"),
cls=_DecimalEncoder,
)
async with charge_point_v201._call_lock:
await charge_point_v201._send(json_data)
assert await wait_for_callerror_and_validate(
test_utility, charge_point_v201, "RpcFrameworkError"
)
# a unknown RPC message should trigger a MessageTypeNotSupported CALLERROR
json_data = json.dumps(
[
99, # should be unknown
"MessageId",
],
# By default json.dumps() adds a white space after every separator.
# By setting the separator manually that can be avoided.
separators=(",", ":"),
cls=_DecimalEncoder,
)
async with charge_point_v201._call_lock:
await charge_point_v201._send(json_data)
assert await wait_for_callerror_and_validate(
test_utility, charge_point_v201, "MessageTypeNotSupported"
)