test_conformance_021.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. # SPDX-License-Identifier: Apache-2.0
  2. # Copyright 2020 Contributors to OpenLEADR
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. # http://www.apache.org/licenses/LICENSE-2.0
  7. # Unless required by applicable law or agreed to in writing, software
  8. # distributed under the License is distributed on an "AS IS" BASIS,
  9. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. # See the License for the specific language governing permissions and
  11. # limitations under the License.
  12. import pytest
  13. from openleadr import OpenADRClient, OpenADRServer, enums
  14. from openleadr.utils import generate_id, datetimeformat, timedeltaformat, booleanformat
  15. from openleadr.messaging import create_message, parse_message
  16. from openleadr.objects import Event, EventDescriptor, ActivePeriod, EventSignal, Interval
  17. from datetime import datetime, timezone, timedelta
  18. import json
  19. import sqlite3
  20. from pprint import pprint
  21. import warnings
  22. VEN_NAME = 'myven'
  23. VTN_ID = "TestVTN"
  24. async def lookup_ven(ven_name=None, ven_id=None):
  25. """
  26. Look up a ven by its name or ID
  27. """
  28. return {'ven_id': '1234'}
  29. async def on_update_report(report, futures=None):
  30. if futures:
  31. futures.pop().set_result(True)
  32. pass
  33. async def on_register_report(report, futures=None):
  34. """
  35. Deal with this report.
  36. """
  37. if futures:
  38. futures.pop().set_result(True)
  39. granularity = min(*[rd['sampling_rate']['min_period'] for rd in report['report_descriptions']])
  40. return (on_update_report, granularity, [rd['r_id'] for rd in report['report_descriptions']])
  41. async def on_create_party_registration(ven_name, future=None):
  42. if future:
  43. future.set_result(True)
  44. ven_id = '1234'
  45. registration_id = 'abcd'
  46. return ven_id, registration_id
  47. class EventFormatter(json.JSONEncoder):
  48. def default(self, obj):
  49. if isinstance(obj, timedelta):
  50. return timedeltaformat(obj)
  51. if isinstance(obj, datetime):
  52. return datetimeformat(obj)
  53. if isinstance(obj, bool):
  54. return booleanformat(obj)
  55. return json.JSONEncoder.default(self, obj)
  56. DB = sqlite3.connect(":memory:")
  57. with DB:
  58. DB.execute("CREATE TABLE vens (ven_id STRING, ven_name STRING, online BOOLEAN, last_seen DATETIME, registration_id STRING)")
  59. DB.execute("CREATE TABLE events (event_id STRING, ven_id STRING, request_id STRING, status STRING, event JSON, created_at DATETIME, updated_at DATETIME)")
  60. def add_ven(ven_name, ven_id, registration_id):
  61. with DB:
  62. DB.execute("""INSERT INTO vens (ven_id, ven_name, online, last_seen, registration_id)
  63. VALUES (?, ?, ?, ?, ?)""", (ven_id, ven_name, True, datetime.now().replace(microsecond=0), registration_id))
  64. def add_event(ven_id, event_id, event):
  65. serialized_event = json.dumps(event, cls=EventFormatter)
  66. with DB:
  67. DB.execute("""INSERT INTO events (ven_id, event_id, request_id, status, event)
  68. VALUES (?, ?, ?, ?, ?)""", (ven_id, event_id, None, 'new', serialized_event))
  69. async def _on_poll(ven_id, request_id=None):
  70. cur = DB.cursor()
  71. cur.execute("""SELECT event_id, event FROM events WHERE ven_id = ? AND status = 'new' LIMIT 1""", (ven_id,))
  72. result = cur.fetchone()
  73. if result:
  74. event_id, event = result
  75. event_request_id = generate_id()
  76. with DB:
  77. DB.execute("""UPDATE events SET request_id = ? WHERE event_id = ?""", (event_request_id, event_id))
  78. response_type = 'oadrDistributeEvent'
  79. response_payload = {'response': {'request_id': request_id,
  80. 'response_code': 200,
  81. 'response_description': 'OK'},
  82. 'request_id': event_request_id,
  83. 'vtn_id': VTN_ID,
  84. 'events': [json.loads(event)]}
  85. else:
  86. response_type = 'oadrResponse'
  87. response_payload = {'response': {'request_id': request_id,
  88. 'response_code': 200,
  89. 'response_description': 'OK'},
  90. 'ven_id': ven_id}
  91. return response_type, response_payload
  92. @pytest.mark.asyncio
  93. async def test_conformance_021():
  94. """
  95. If venID, vtnID, or eventID value is included in the payload, the receiving
  96. entity MUST validate that the ID value is as expected and generate an error
  97. if an unexpected value is received.
  98. Exception: A VEN MUST NOT generate an error upon receipt of a canceled
  99. event whose eventID is not previously known.
  100. """
  101. server = OpenADRServer(vtn_id='TestVTN', http_port=8001)
  102. server.add_handler('on_create_party_registration', on_create_party_registration)
  103. server.add_handler('on_poll', _on_poll)
  104. await server.run_async()
  105. client = OpenADRClient(ven_name="TestVEN",
  106. vtn_url="http://localhost:8001/OpenADR2/Simple/2.0b")
  107. await client.create_party_registration()
  108. event = {'event_descriptor':
  109. {'event_id': generate_id(),
  110. 'modification_number': 0,
  111. 'modification_date': datetime.now(),
  112. 'priority': 0,
  113. 'market_context': 'MarketContext001',
  114. 'created_date_time': datetime.now(),
  115. 'event_status': enums.EVENT_STATUS.FAR,
  116. 'test_event': False,
  117. 'vtn_comment': 'No Comment'},
  118. 'active_period':
  119. {'dtstart': datetime.now() + timedelta(minutes=30),
  120. 'duration': timedelta(minutes=30)},
  121. 'event_signals':
  122. [{'intervals': [{'duration': timedelta(minutes=10),
  123. 'signal_payload': 1},
  124. {'duration': timedelta(minutes=10),
  125. 'signal_payload': 2},
  126. {'duration': timedelta(minutes=10),
  127. 'signal_payload': 3}],
  128. 'signal_name': enums.SIGNAL_NAME.SIMPLE,
  129. 'signal_type': enums.SIGNAL_TYPE.DELTA,
  130. 'signal_id': generate_id(),
  131. 'current_value': 123
  132. }],
  133. 'targets': [{'ven_id': '123'}]
  134. }
  135. add_event(ven_id=client.ven_id,
  136. event_id = event['event_descriptor']['event_id'],
  137. event=event)
  138. message_type, message_payload = await client.poll()
  139. assert message_type == 'oadrDistributeEvent'
  140. await client.stop()
  141. await server.stop()