소스 검색

Added conformance test 008, added preflight mechanism for outgoing messages

Stan Janssen 4 년 전
부모
커밋
1eb16d3649
5개의 변경된 파일145개의 추가작업 그리고 2개의 파일을 삭제
  1. 30 0
      pyopenadr/preflight.py
  2. 3 0
      pyopenadr/utils.py
  3. 1 1
      test/conformance/test_conformance_002.py
  4. 1 1
      test/conformance/test_conformance_006.py
  5. 110 0
      test/conformance/test_conformance_008.py

+ 30 - 0
pyopenadr/preflight.py

@@ -0,0 +1,30 @@
+"""
+Tests message contents before sending them. It will correct benign errors and
+warn you about them. Uncorrectable errors will raise an Exception.
+"""
+from datetime import timedelta
+import warnings
+
+def preflight_message(message_type, message_payload):
+    if f'preflight_{message_type}' in globals():
+        message_payload = globals()[f'preflight_{message_type}'](message_payload)
+    return message_type, message_payload
+
+def preflight_oadrDistributeEvent(message_payload):
+    # Check that the total event_duration matches the sum of the interval durations (rule 8)
+    for event in message_payload['events']:
+        active_period_duration = event['active_period']['duration']
+        signal_durations = []
+        for signal in event['event_signals']:
+            signal_durations.append(sum([i['duration'] for i in signal['intervals']], timedelta(seconds=0)))
+
+
+        if not all([d==active_period_duration for d in signal_durations]):
+            if not all([d==signal_durations[0] for d in signal_durations]):
+                raise ValueError("The different EventSignals have different total durations. Please correct this.")
+            else:
+                warnings.warn(f"The active_period duration for event {event['event_descriptor']['event_id']} ({active_period_duration})"
+                              f" was different from the sum of the interval's durations ({signal_durations[0]})."
+                              f" The active_period duration has been adjusted to ({signal_durations[0]}).")
+                event['active_period']['duration'] = signal_durations[0]
+

+ 3 - 0
pyopenadr/utils.py

@@ -8,6 +8,8 @@ from collections import OrderedDict
 import itertools
 import re
 
+from .preflight import preflight_message
+
 DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ"
 DATETIME_FORMAT_NO_MICROSECONDS = "%Y-%m-%dT%H:%M:%SZ"
 
@@ -258,6 +260,7 @@ def parse_message(data):
     return message_type, normalize_dict(message_payload)
 
 def create_message(message_type, **message_payload):
+    preflight_message(message_type, message_payload)
     template = TEMPLATES.get_template(f'{message_type}.xml')
     return indent_xml(template.render(**message_payload))
 

+ 1 - 1
test/conformance/test_conformance_002.py

@@ -28,7 +28,7 @@ async def test_conformance_002():
                  'vtn_comment': 'No Comment'},
             'active_period':
                 {'dtstart': datetime.now(),
-                 'duration': timedelta(minutes=5)},
+                 'duration': timedelta(minutes=30)},
             'event_signals':
                 [{'intervals': [{'duration': timedelta(minutes=10),
                                  'signal_payload': 100},

+ 1 - 1
test/conformance/test_conformance_006.py

@@ -26,7 +26,7 @@ async def test_conformance_006():
                  'vtn_comment': 'No Comment'},
             'active_period':
                 {'dtstart': datetime.now(),
-                 'duration': timedelta(minutes=5)},
+                 'duration': timedelta(minutes=30)},
             'event_signals':
                 [{'intervals': [{'duration': timedelta(minutes=10),
                                  'signal_payload': 100},

+ 110 - 0
test/conformance/test_conformance_008.py

@@ -0,0 +1,110 @@
+import pytest
+
+from pyopenadr import OpenADRClient, OpenADRServer, enums
+from pyopenadr.utils import generate_id, create_message, parse_message
+from datetime import datetime, timezone, timedelta
+
+from pprint import pprint
+import warnings
+
+
+@pytest.mark.asyncio
+async def test_conformance_008_autocorrect():
+    """
+    oadrDistributeEvent eventSignal interval durations for a given event MUST
+    add up to eiEvent eiActivePeriod duration.
+    """
+    event_id = generate_id()
+    event = {'event_descriptor':
+                {'event_id': event_id,
+                 'modification_number': 0,
+                 'modification_date': datetime.now(),
+                 'priority': 0,
+                 'market_context': 'MarketContext001',
+                 'created_date_time': datetime.now(),
+                 'event_status': enums.EVENT_STATUS.FAR,
+                 'test_event': "HelloThere",
+                 'vtn_comment': 'No Comment'},
+            'active_period':
+                {'dtstart': datetime.now(),
+                 'duration': timedelta(minutes=5)},
+            'event_signals':
+                [{'intervals': [{'duration': timedelta(minutes=10),
+                                 'signal_payload': 100},
+                                {'duration': timedelta(minutes=10),
+                                 'signal_payload': 200},
+                                {'duration': timedelta(minutes=10),
+                                 'signal_payload': 300}],
+                  'signal_name': enums.SIGNAL_NAME.SIMPLE,
+                  'signal_type': enums.SIGNAL_TYPE.DELTA,
+                  'signal_id': generate_id()
+                }]
+        }
+
+    # Create a message with this event
+    with pytest.warns(UserWarning):
+        msg = create_message('oadrDistributeEvent',
+                             response={'response_code': 200,
+                                       'response_description': 'OK',
+                                       'request_id': generate_id()},
+                             request_id=generate_id(),
+                             vtn_id=generate_id(),
+                             events=[event])
+
+    parsed_type, parsed_msg = parse_message(msg)
+    assert parsed_type == 'oadrDistributeEvent'
+    total_time = sum([i['duration'] for i in parsed_msg['events'][0]['event_signals'][0]['intervals']],
+                     timedelta(seconds=0))
+    assert parsed_msg['events'][0]['active_period']['duration'] == total_time
+
+@pytest.mark.asyncio
+async def test_conformance_008_raise():
+    """
+    oadrDistributeEvent eventSignal interval durations for a given event MUST
+    add up to eiEvent eiActivePeriod duration.
+    """
+    event_id = generate_id()
+    event = {'event_descriptor':
+                {'event_id': event_id,
+                 'modification_number': 0,
+                 'modification_date': datetime.now(),
+                 'priority': 0,
+                 'market_context': 'MarketContext001',
+                 'created_date_time': datetime.now(),
+                 'event_status': enums.EVENT_STATUS.FAR,
+                 'test_event': "HelloThere",
+                 'vtn_comment': 'No Comment'},
+            'active_period':
+                {'dtstart': datetime.now(),
+                 'duration': timedelta(minutes=5)},
+            'event_signals':
+                [{'intervals': [{'duration': timedelta(minutes=10),
+                                 'signal_payload': 100},
+                                {'duration': timedelta(minutes=10),
+                                 'signal_payload': 200},
+                                {'duration': timedelta(minutes=10),
+                                 'signal_payload': 300}],
+                  'signal_name': enums.SIGNAL_NAME.SIMPLE,
+                  'signal_type': enums.SIGNAL_TYPE.DELTA,
+                  'signal_id': generate_id()
+                },
+                {'intervals': [{'duration': timedelta(minutes=1),
+                                 'signal_payload': 100},
+                                {'duration': timedelta(minutes=2),
+                                 'signal_payload': 200},
+                                {'duration': timedelta(minutes=2),
+                                 'signal_payload': 300}],
+                  'signal_name': enums.SIGNAL_NAME.SIMPLE,
+                  'signal_type': enums.SIGNAL_TYPE.DELTA,
+                  'signal_id': generate_id()
+                }]
+        }
+
+    with pytest.raises(ValueError):
+        msg = create_message('oadrDistributeEvent',
+                             response={'response_code': 200,
+                                       'response_description': 'OK',
+                                       'request_id': generate_id()},
+                             request_id=generate_id(),
+                             vtn_id=generate_id(),
+                             events=[event])