Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def test_validate_payload_with_non_existing_schema():
"""
Test if correct exception is raised when a validation schema cannot be
found.
"""
message = CallResult(
unique_id="1234",
action="MagicSpell",
payload={'invalid_key': True},
)
with pytest.raises(ValidationError):
validate_payload(message, ocpp_version="1.6")
def test_validate_payload_with_invalid_payload():
"""
Test if validate_payload raises ValidationError when validation of
payload failes.
"""
message = CallResult(
unique_id="1234",
action="Heartbeat",
payload={'invalid_key': True},
)
with pytest.raises(ValidationError):
validate_payload(message, ocpp_version="1.6")
def test_validate_payload_with_invalid_message_type_id():
"""
Test if validate_payload raises ValidationError when it is called with
a message type id other than 2, Call, or 3, CallError.
"""
with pytest.raises(ValidationError):
validate_payload(dict(), ocpp_version="1.6")
def test_validate_payload_with_valid_payload(ocpp_version):
"""
Test if validate_payload doesn't return any exceptions when it's
validating a valid payload.
"""
message = CallResult(
unique_id="1234",
action="Heartbeat",
payload={'currentTime': datetime.now().isoformat()}
)
validate_payload(message, ocpp_version=ocpp_version)
'stackLevel': 0,
'chargingProfilePurpose': 'TxProfile',
'chargingProfileKind': 'Relative',
'chargingSchedule': {
'chargingRateUnit': 'A',
'chargingSchedulePeriod': [{
'startPeriod': 0,
'limit': 21.4
}]
},
'transactionId': 123456789,
}
}
)
validate_payload(message, ocpp_version="1.6")
First the '_on_action' hook is executed and its response is returned to
the client. If there is no '_on_action' hook for Action in the message
a CallError with a NotImplemtendError is returned.
Next the '_after_action' hook is executed.
"""
try:
handlers = self.route_map[msg.action]
except KeyError:
raise NotImplementedError(f"No handler for '{msg.action}' "
"registered.")
if not handlers.get('_skip_schema_validation', False):
validate_payload(msg, self._ocpp_version)
# OCPP uses camelCase for the keys in the payload. It's more pythonic
# to use snake_case for keyword arguments. Therefore the keys must be
# 'translated'. Some examples:
#
# * chargePointVendor becomes charge_point_vendor
# * firmwareVersion becomes firmwareVersion
snake_case_payload = camel_to_snake_case(msg.payload)
try:
handler = handlers['_on_action']
except KeyError:
raise NotImplementedError(f"No handler for '{msg.action}' "
"registered.")
try:
# Remove nones ensures that we strip out optional arguments
# which were not set and have a default value of None
response_payload = remove_nones(temp_response_payload)
# The response payload must be 'translated' from snake_case to
# camelCase. So:
#
# * charge_point_vendor becomes chargePointVendor
# * firmware_version becomes firmwareVersion
camel_case_payload = snake_to_camel_case(response_payload)
response = msg.create_call_result(camel_case_payload)
if not handlers.get('_skip_schema_validation', False):
validate_payload(response, self._ocpp_version)
await self._send(response.to_json())
try:
handler = handlers['_after_action']
# Create task to avoid blocking when making a call inside the
# after handler
asyncio.ensure_future(
asyncio.coroutine(handler)(**snake_case_payload))
except KeyError:
# '_on_after' hooks are not required. Therefore ignore exception
# when no '_on_after' hook is installed.
pass
)
# Use a lock to prevent make sure that only 1 message can be send at a
# a time.
async with self._call_lock:
await self._send(call.to_json())
response = \
await self._get_specific_response(call.unique_id,
self._response_timeout)
if response.message_type_id == MessageType.CallError:
LOGGER.warning("Received a CALLError: %s'", response)
return
else:
response.action = call.action
validate_payload(response, self._ocpp_version)
snake_case_payload = camel_to_snake_case(response.payload)
# Create the correct Payload instance based on the received payload. If
# this method is called with a call.BootNotificationPayload, then it
# will create a call_result.BootNotificationPayload. If this method is
# called with a call.HeartbeatPayload, then it will create a
# call_result.HeartbeatPayload etc.
cls = getattr(self._call_result, payload.__class__.__name__) # noqa
return cls(**snake_case_payload)