3
3
import pytest
4
4
5
5
from ocpp .charge_point import camel_to_snake_case , remove_nones , snake_to_camel_case
6
- from ocpp .routing import create_route_map , on
6
+ from ocpp .messages import Call
7
+ from ocpp .routing import after , create_route_map , on
8
+ from ocpp .v16 import ChargePoint as cp_16
7
9
from ocpp .v16 .call import (
8
10
BootNotificationPayload ,
9
11
GetConfigurationPayload ,
10
12
MeterValuesPayload ,
11
13
)
14
+ from ocpp .v16 .call_result import (
15
+ BootNotificationPayload as BootNotificationResultPayload ,
16
+ )
12
17
from ocpp .v16 .datatypes import MeterValue , SampledValue
13
- from ocpp .v16 .enums import Action
14
- from ocpp .v20 import ChargePoint as cp
18
+ from ocpp .v16 .enums import Action , RegistrationStatus
19
+ from ocpp .v20 import ChargePoint as cp_20
15
20
from ocpp .v201 .call import SetNetworkProfilePayload
16
21
from ocpp .v201 .datatypes import NetworkConnectionProfileType
17
22
from ocpp .v201 .enums import OCPPInterfaceType , OCPPTransportType , OCPPVersionType
18
23
19
24
20
25
def test_getters_should_not_be_called_during_routemap_setup ():
21
- class ChargePoint (cp ):
26
+ class ChargePoint (cp_20 ):
22
27
@property
23
28
def foo (self ):
24
29
raise RuntimeError ("this will be raised" )
@@ -31,12 +36,12 @@ def foo(self):
31
36
32
37
33
38
def test_multiple_classes_with_same_name_for_handler ():
34
- class ChargerA (cp ):
39
+ class ChargerA (cp_20 ):
35
40
@on (Action .Heartbeat )
36
41
def heartbeat (self , ** kwargs ):
37
42
pass
38
43
39
- class ChargerB (cp ):
44
+ class ChargerB (cp_20 ):
40
45
@on (Action .Heartbeat )
41
46
def heartbeat (self , ** kwargs ):
42
47
pass
@@ -232,3 +237,101 @@ def test_remove_nones_with_list_of_strings():
232
237
assert remove_nones (payload ) == {
233
238
"key" : ["ClockAlignedDataInterval" , "ConnectionTimeOut" ]
234
239
}
240
+
241
+
242
+ @pytest .mark .asyncio
243
+ async def test_call_unique_id_added_to_handler_args_correctly (connection ):
244
+ """
245
+ This test ensures that the `call_unique_id` is getting passed to the
246
+ `on` and `after` handlers only if it is explicitly set in the handler signature.
247
+
248
+ To cover all possible cases, we define two chargers:
249
+
250
+ ChargerA:
251
+ `call_unique_id` not required on `on` handler but required on `after` handler.
252
+
253
+ ChargerB:
254
+ `call_unique_id` required on `on` handler but not required on `after` handler.
255
+
256
+ Each handler verifies a set of asserts to verify that the `call_unique_id`
257
+ is passed correctly.
258
+ To confirm that the handlers are actually being called and hence the asserts
259
+ are being ran, we introduce a set of counters that increase each time a specific
260
+ handler runs.
261
+ """
262
+ charger_a_test_call_unique_id = "charger_a_1234"
263
+ charger_b_test_call_unique_id = "charger_b_5678"
264
+ payload_a = {"chargePointVendor" : "foo_a" , "chargePointModel" : "bar_a" }
265
+ payload_b = {"chargePointVendor" : "foo_b" , "chargePointModel" : "bar_b" }
266
+
267
+ class ChargerA (cp_16 ):
268
+ on_boot_notification_call_count = 0
269
+ after_boot_notification_call_count = 0
270
+
271
+ @on (Action .BootNotification )
272
+ def on_boot_notification (self , * args , ** kwargs ):
273
+ # call_unique_id should not be passed as arg nor kwarg
274
+ assert kwargs == camel_to_snake_case (payload_a )
275
+ assert args == ()
276
+ ChargerA .on_boot_notification_call_count += 1
277
+ return BootNotificationResultPayload (
278
+ current_time = "foo" , interval = 1 , status = RegistrationStatus .accepted
279
+ )
280
+
281
+ @after (Action .BootNotification )
282
+ def after_boot_notification (self , call_unique_id , * args , ** kwargs ):
283
+ assert call_unique_id == charger_a_test_call_unique_id
284
+ assert kwargs == camel_to_snake_case (payload_a )
285
+ # call_unique_id should not be passed as arg
286
+ assert args == ()
287
+ ChargerA .after_boot_notification_call_count += 1
288
+ return BootNotificationResultPayload (
289
+ current_time = "foo" , interval = 1 , status = RegistrationStatus .accepted
290
+ )
291
+
292
+ class ChargerB (cp_16 ):
293
+ on_boot_notification_call_count = 0
294
+ after_boot_notification_call_count = 0
295
+
296
+ @on (Action .BootNotification )
297
+ def on_boot_notification (self , call_unique_id , * args , ** kwargs ):
298
+ assert call_unique_id == charger_b_test_call_unique_id
299
+ assert kwargs == camel_to_snake_case (payload_b )
300
+ # call_unique_id should not be passed as arg
301
+ assert args == ()
302
+ ChargerB .on_boot_notification_call_count += 1
303
+ return BootNotificationResultPayload (
304
+ current_time = "foo" , interval = 1 , status = RegistrationStatus .accepted
305
+ )
306
+
307
+ @after (Action .BootNotification )
308
+ def after_boot_notification (self , * args , ** kwargs ):
309
+ # call_unique_id should not be passed as arg nor kwarg
310
+ assert kwargs == camel_to_snake_case (payload_b )
311
+ assert args == ()
312
+ ChargerB .after_boot_notification_call_count += 1
313
+ return BootNotificationResultPayload (
314
+ current_time = "foo" , interval = 1 , status = RegistrationStatus .accepted
315
+ )
316
+
317
+ charger_a = ChargerA ("charger_a_id" , connection )
318
+ charger_b = ChargerB ("charger_b_id" , connection )
319
+
320
+ msg_a = Call (
321
+ unique_id = charger_a_test_call_unique_id ,
322
+ action = Action .BootNotification .value ,
323
+ payload = payload_a ,
324
+ )
325
+ await charger_a ._handle_call (msg_a )
326
+
327
+ msg_b = Call (
328
+ unique_id = charger_b_test_call_unique_id ,
329
+ action = Action .BootNotification .value ,
330
+ payload = payload_b ,
331
+ )
332
+ await charger_b ._handle_call (msg_b )
333
+
334
+ assert ChargerA .on_boot_notification_call_count == 1
335
+ assert ChargerA .after_boot_notification_call_count == 1
336
+ assert ChargerB .on_boot_notification_call_count == 1
337
+ assert ChargerB .after_boot_notification_call_count == 1
0 commit comments