Ejemplo n.º 1
0
async def test_update_reports():
    """
    Tests the timely delivery of requested reports
    """
    # Create a server
    logger = logging.getLogger('openleadr')
    logger.setLevel(logging.DEBUG)
    loop = asyncio.get_event_loop()
    server = OpenADRServer(vtn_id='testvtn')

    register_report_future_1 = loop.create_future()
    register_report_future_2 = loop.create_future()
    register_report_futures = [
        register_report_future_1, register_report_future_2
    ]

    receive_report_future_1 = loop.create_future()
    receive_report_future_2 = loop.create_future()
    receive_report_future_3 = loop.create_future()
    receive_report_future_4 = loop.create_future()
    receive_report_futures = [
        receive_report_future_1, receive_report_future_2,
        receive_report_future_3, receive_report_future_4
    ]
    server.add_handler(
        'on_register_report',
        partial(on_register_report,
                futures=register_report_futures,
                receive_futures=receive_report_futures))

    party_future = loop.create_future()
    server.add_handler(
        'on_create_party_registration',
        partial(on_create_party_registration, future=party_future))

    # Create a client
    client = OpenADRClient(
        ven_name='myven', vtn_url='http://localhost:8080/OpenADR2/Simple/2.0b')

    # Add 4 reports
    future_1 = loop.create_future()
    client.add_report(callback=partial(collect_data, future=future_1),
                      report_specifier_id='PowerReport',
                      resource_id='Device001',
                      measurement='power_real',
                      sampling_rate=timedelta(seconds=2),
                      unit='W')
    future_2 = loop.create_future()
    client.add_report(callback=partial(collect_data, future=future_2),
                      report_specifier_id='PowerReport',
                      resource_id='Device002',
                      measurement='power_real',
                      sampling_rate=timedelta(seconds=2),
                      unit='W')
    future_3 = loop.create_future()
    client.add_report(callback=partial(collect_data, future=future_3),
                      report_specifier_id='VoltageReport',
                      resource_id='Device001',
                      measurement='voltage',
                      sampling_rate=timedelta(seconds=2),
                      unit='V')
    future_4 = loop.create_future()
    client.add_report(callback=partial(collect_data, future=future_4),
                      report_specifier_id='VoltageReport',
                      resource_id='Device002',
                      measurement='voltage',
                      sampling_rate=timedelta(seconds=2),
                      unit='V')

    assert len(client.reports) == 2
    asyncio.create_task(server.run_async())
    await asyncio.sleep(1)

    # Run the client asynchronously
    print("Running the client")
    asyncio.create_task(client.run())

    print("Awaiting party future")
    await party_future

    print("Awaiting report futures")
    await asyncio.gather(register_report_future_1, register_report_future_2)
    await asyncio.sleep(0.1)
    assert len(server.services['report_service'].report_callbacks) == 4

    print("Awaiting data collection futures")
    await future_1
    await future_2
    await future_3
    await future_4

    print("Awaiting update report futures")
    await asyncio.gather(receive_report_future_1, receive_report_future_2,
                         receive_report_future_3, receive_report_future_4)
    print("Done gathering")

    assert receive_report_future_1.result()[0][1] == future_1.result()
    assert receive_report_future_2.result()[0][1] == future_2.result()
    assert receive_report_future_3.result()[0][1] == future_3.result()
    assert receive_report_future_4.result()[0][1] == future_4.result()

    await client.stop()
    await server.stop()
Ejemplo n.º 2
0
            'response_description': 'OK',
            'request_id': payload['request_id']
        },
        'ven_id':
        ven_id,
        'registration_id':
        registration_id,
        'profiles': [{
            'profile_name': '2.0b',
            'transports': {
                'transport_name': 'simpleHttp'
            }
        }],
        'requested_oadr_poll_freq':
        timedelta(seconds=10)
    }
    return 'oadrCreatedPartyRegistration', payload


server = OpenADRServer(vtn_id=VTN_ID, http_port=SERVER_PORT)
server.add_handler('on_create_party_registration',
                   _on_create_party_registration)
server.add_handler('on_poll', _on_poll)


@pytest.fixture
async def start_server():
    await server.run_async()
    yield
    await server.stop()
Ejemplo n.º 3
0
async def test_event_external_polling_function():
    async def opt_in_to_event(event, future=None):
        if future:
            future.set_result(True)
        return 'optIn'

    async def on_update_event(event, future=None):
        if future:
            future.set_result(event)
        return 'optIn'

    async def on_poll(ven_id, future=None):
        if future and not future.done():
            future.set_result(True)
            return objects.Event(
                event_descriptor=objects.EventDescriptor(
                    event_id='event001',
                    modification_number=0,
                    event_status='far',
                    market_context='http://marketcontext01'),
                event_signals=[
                    objects.EventSignal(
                        signal_id='signal001',
                        signal_type='level',
                        signal_name='simple',
                        intervals=[
                            objects.Interval(
                                dtstart=now,
                                duration=datetime.timedelta(minutes=10),
                                signal_payload=1)
                        ]),
                    objects.EventSignal(
                        signal_id='signal002',
                        signal_type='price',
                        signal_name='ELECTRICITY_PRICE',
                        intervals=[
                            objects.Interval(
                                dtstart=now,
                                duration=datetime.timedelta(minutes=10),
                                signal_payload=1)
                        ])
                ],
                targets=[objects.Target(ven_id=ven_id)])
        else:
            print("Returning None")
            return None

    loop = asyncio.get_event_loop()
    now = datetime.datetime.now(datetime.timezone.utc)
    server = OpenADRServer(vtn_id='myvtn',
                           requested_poll_freq=datetime.timedelta(seconds=1))
    server.add_handler('on_create_party_registration',
                       on_create_party_registration)
    poll_fut = loop.create_future()
    server.add_handler('on_poll', partial(on_poll, future=poll_fut))
    await server.run()

    client = OpenADRClient(
        ven_name='ven123',
        vtn_url='http://localhost:8080/OpenADR2/Simple/2.0b')
    fut = loop.create_future()
    client.add_handler('on_event', partial(opt_in_to_event, future=fut))
    await client.run()
    await fut

    assert len(client.responded_events) == 1
    assert len(client.received_events) == 1

    await server.stop()
    await client.stop()
Ejemplo n.º 4
0
async def test_multiple_events_in_queue():
    now = datetime.datetime.now(datetime.timezone.utc)
    server = OpenADRServer(vtn_id='myvtn')
    server.add_handler('on_create_party_registration',
                       on_create_party_registration)

    loop = asyncio.get_event_loop()
    event_1_callback_future = loop.create_future()
    event_2_callback_future = loop.create_future()
    server.add_event(ven_id='ven123',
                     signal_name='simple',
                     signal_type='level',
                     intervals=[
                         objects.Interval(
                             dtstart=now,
                             duration=datetime.timedelta(seconds=1),
                             signal_payload=1)
                     ],
                     callback=event_1_callback_future)

    await server.run()

    on_event_future = loop.create_future()
    client = OpenADRClient(
        ven_name='ven123',
        vtn_url='http://localhost:8080/OpenADR2/Simple/2.0b')
    await client.create_party_registration()
    response_type, response_payload = await client.request_event()
    assert response_type == 'oadrDistributeEvent'
    events = response_payload['events']
    assert len(events) == 1
    event_id = events[0]['event_descriptor']['event_id']
    request_id = response_payload['request_id']
    await client.created_event(request_id=request_id,
                               event_id=event_id,
                               opt_type='optIn',
                               modification_number=0)

    server.add_event(ven_id='ven123',
                     signal_name='simple',
                     signal_type='level',
                     intervals=[
                         objects.Interval(
                             dtstart=now + datetime.timedelta(seconds=1),
                             duration=datetime.timedelta(seconds=1),
                             signal_payload=1)
                     ],
                     callback=event_2_callback_future)
    response_type, response_payload = await client.request_event()
    assert response_type == 'oadrDistributeEvent'
    events = response_payload['events']

    # Assert that we still have two events in the response
    assert len(events) == 2

    # Wait one second and retrieve the events again
    await asyncio.sleep(1)
    response_type, response_payload = await client.request_event()
    assert response_type == 'oadrDistributeEvent'
    events = response_payload['events']
    assert len(events) == 2
    assert events[1]['event_descriptor']['event_status'] == 'completed'

    response_type, response_payload = await client.request_event()
    assert response_type == 'oadrDistributeEvent'
    events = response_payload['events']
    assert len(events) == 1
    await asyncio.sleep(1)

    response_type, response_payload = await client.request_event()
    assert response_type == 'oadrDistributeEvent'

    response_type, response_payload = await client.request_event()
    assert response_type == 'oadrResponse'

    await server.stop()
Ejemplo n.º 5
0
        ven_id,
        'registration_id':
        registration_id,
        'profiles': [{
            'profile_name': '2.0b',
            'transports': {
                'transport_name': 'simpleHttp'
            }
        }],
        'requested_oadr_poll_freq':
        timedelta(seconds=10)
    }
    return 'oadrCreatedPartyRegistration', payload


server = OpenADRServer(vtn_id=VTN_ID)
server.add_handler('on_create_party_registration',
                   _on_create_party_registration)
server.add_handler('on_poll', _on_poll)


@pytest.fixture
async def start_server():
    runner = web.AppRunner(server.app)
    await runner.setup()
    site = web.TCPSite(runner, 'localhost', SERVER_PORT)
    await site.start()
    print("SERVER IS NOW RUNNING")
    yield
    print("SERVER IS NOW STOPPING")
    await runner.cleanup()
Ejemplo n.º 6
0
async def test_report_registration_broken_handlers_raw_message(caplog):
    msg = """<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<p1:oadrPayload xmlns:p1="http://openadr.org/oadr-2.0b/2012/07">
  <p1:oadrSignedObject>
    <p1:oadrRegisterReport xmlns:p3="http://docs.oasis-open.org/ns/energyinterop/201110" p3:schemaVersion="2.0b" xmlns:p2="http://docs.oasis-open.org/ns/energyinterop/201110/payloads">
      <p2:requestID>B8A6E0D2D4</p2:requestID>
      <p1:oadrReport xmlns:p3="urn:ietf:params:xml:ns:icalendar-2.0" xmlns:p4="http://docs.oasis-open.org/ns/energyinterop/201110">
        <p3:duration>
          <p3:duration>PT120M</p3:duration>
        </p3:duration>
        <p1:oadrReportDescription xmlns:p4="http://docs.oasis-open.org/ns/energyinterop/201110" xmlns:p5="http://docs.oasis-open.org/ns/emix/2011/06/power" xmlns:p6="http://docs.oasis-open.org/ns/emix/2011/06">
          <p4:rID>rid_energy_4184bb93</p4:rID>
          <p4:reportDataSource>
            <p4:resourceID>DEVICE1</p4:resourceID>
          </p4:reportDataSource>
          <p4:reportType>reading</p4:reportType>
          <p5:energyReal xmlns:p6="http://docs.oasis-open.org/ns/emix/2011/06/siscale">
            <p5:itemDescription/>
            <p5:itemUnits>Wh</p5:itemUnits>
            <p6:siScaleCode>none</p6:siScaleCode>
          </p5:energyReal>
          <p4:readingType>Direct Read</p4:readingType>
          <p6:marketContext/>
          <p1:oadrSamplingRate>
            <p1:oadrMinPeriod>PT1M</p1:oadrMinPeriod>
            <p1:oadrMaxPeriod>PT1M</p1:oadrMaxPeriod>
            <p1:oadrOnChange>false</p1:oadrOnChange>
          </p1:oadrSamplingRate>
        </p1:oadrReportDescription>
        <p1:oadrReportDescription xmlns:p4="http://docs.oasis-open.org/ns/energyinterop/201110" xmlns:p5="http://docs.oasis-open.org/ns/emix/2011/06/power" xmlns:p6="http://docs.oasis-open.org/ns/emix/2011/06">
          <p4:rID>rid_power_4184bb93</p4:rID>
          <p4:reportDataSource>
            <p4:resourceID>DEVICE1</p4:resourceID>
          </p4:reportDataSource>
          <p4:reportType>reading</p4:reportType>
          <p5:powerReal xmlns:p6="http://docs.oasis-open.org/ns/emix/2011/06/siscale">
            <p5:itemDescription/>
            <p5:itemUnits>W</p5:itemUnits>
            <p6:siScaleCode>none</p6:siScaleCode>
            <p5:powerAttributes>
              <p5:hertz>60</p5:hertz>
              <p5:voltage>120</p5:voltage>
              <p5:ac>true</p5:ac>
            </p5:powerAttributes>
          </p5:powerReal>
          <p4:readingType>Direct Read</p4:readingType>
          <p6:marketContext/>
          <p1:oadrSamplingRate>
            <p1:oadrMinPeriod>PT1M</p1:oadrMinPeriod>
            <p1:oadrMaxPeriod>PT1M</p1:oadrMaxPeriod>
            <p1:oadrOnChange>false</p1:oadrOnChange>
          </p1:oadrSamplingRate>
        </p1:oadrReportDescription>
        <p4:reportRequestID>0</p4:reportRequestID>
        <p4:reportSpecifierID>DEMO_TELEMETRY_USAGE</p4:reportSpecifierID>
        <p4:reportName>METADATA_TELEMETRY_USAGE</p4:reportName>
        <p4:createdDateTime>2020-12-15T14:10:32Z</p4:createdDateTime>
      </p1:oadrReport>
      <p3:venID>ven_id</p3:venID>
    </p1:oadrRegisterReport>
  </p1:oadrSignedObject>
</p1:oadrPayload>"""
    server = OpenADRServer(vtn_id='myvtn')
    await server.run()


    # Test with no configured callbacks

    from aiohttp import ClientSession
    async with ClientSession() as session:
        async with session.post("http://localhost:8080/OpenADR2/Simple/2.0b/EiReport",
                                  headers={'content-type': 'Application/XML'},
                                  data=msg.encode('utf-8')) as resp:
            assert resp.status == 200


    # Test with a working callback

    def report_callback(data):
        print(data)

    def working_on_register_report(ven_id, resource_id, measurement, unit, scale, min_sampling_interval, max_sampling_interval):
        return report_callback, min_sampling_interval

    server.add_handler('on_register_report', working_on_register_report)
    async with ClientSession() as session:
        async with session.post("http://localhost:8080/OpenADR2/Simple/2.0b/EiReport",
                                  headers={'content-type': 'Application/XML'},
                                  data=msg.encode('utf-8')) as resp:
            assert resp.status == 200


    # Test with a broken callback

    def broken_on_register_report(ven_id, resource_id, measurement, unit, scale, min_sampling_interval, max_sampling_interval):
        return "Hello There"

    server.add_handler('on_register_report', broken_on_register_report)
    async with ClientSession() as session:
        async with session.post("http://localhost:8080/OpenADR2/Simple/2.0b/EiReport",
                                  headers={'content-type': 'Application/XML'},
                                  data=msg.encode('utf-8')) as resp:
            assert resp.status == 200

    # assert "Your on_register_report handler must return a tuple; it returned 'Hello There' (str)." in caplog.messages


    # Test with a broken full callback

    def broken_on_register_report_full(report):
        return "Hello There Again"

    server.add_handler('on_register_report', broken_on_register_report_full)
    async with ClientSession() as session:
        async with session.post("http://localhost:8080/OpenADR2/Simple/2.0b/EiReport",
                                  headers={'content-type': 'Application/XML'},
                                  data=msg.encode('utf-8')) as resp:
            assert resp.status == 200

    assert f"Your on_register_report handler must return a list of tuples or None; it returned 'Hello There Again' (str)." in caplog.messages

    await server.stop()
Ejemplo n.º 7
0
async def test_different_on_register_report_handlers(caplog):
    def on_create_party_registration(registration_info):
        return 'ven123', 'reg123'

    def get_value():
        return 123.456

    def report_callback(data):
        pass

    def on_register_report_returning_none(ven_id, resource_id, measurement, unit, scale, min_sampling_interval, max_sampling_interval):
        return None

    def on_register_report_returning_string(ven_id, resource_id, measurement, unit, scale, min_sampling_interval, max_sampling_interval):
        return "Hello There"

    def on_register_report_returning_uncallable_first_element(ven_id, resource_id, measurement, unit, scale, min_sampling_interval, max_sampling_interval):
        return ("Hello", "There")

    def on_register_report_returning_non_datetime_second_element(ven_id, resource_id, measurement, unit, scale, min_sampling_interval, max_sampling_interval):
        return (report_callback, "Hello There")

    def on_register_report_returning_non_datetime_third_element(ven_id, resource_id, measurement, unit, scale, min_sampling_interval, max_sampling_interval):
        return (report_callback, timedelta(minutes=10), "Hello There")

    def on_register_report_returning_too_long_tuple(ven_id, resource_id, measurement, unit, scale, min_sampling_interval, max_sampling_interval):
        return (report_callback, timedelta(minutes=10), timedelta(minutes=10), "Hello")

    def on_register_report_full_returning_string(report):
        return "Hello There"

    def on_register_report_full_returning_list_of_strings(report):
        return ["Hello", "There"]

    def on_register_report_full_returning_list_of_tuples_of_wrong_length(report):
        return [("Hello", "There")]

    def on_register_report_full_returning_list_of_tuples_with_no_callable(report):
        return [("Hello", "There", "World")]

    def on_register_report_full_returning_list_of_tuples_with_no_timedelta(report):
        return [(report_callback, "Hello There")]

    server = OpenADRServer(vtn_id='myvtn')
    server.add_handler('on_create_party_registration', on_create_party_registration)

    client = OpenADRClient(ven_name='myven',
                           vtn_url='http://localhost:8080/OpenADR2/Simple/2.0b')
    client.add_report(resource_id='Device001',
                      measurement='voltage',
                      sampling_rate=timedelta(minutes=10),
                      callback=get_value)

    await server.run()
    await client.create_party_registration()
    assert client.ven_id == 'ven123'
    caplog.clear()

    await client.register_reports(client.reports)
    assert len(client.report_requests) == 0
    messages = [rec.message for rec in caplog.records if rec.levelno == logging.ERROR]
    assert len(messages) == 0
    caplog.clear()

    server.add_handler('on_register_report', on_register_report_returning_none)
    await client.register_reports(client.reports)
    assert len(client.report_requests) == 0
    messages = [rec.message for rec in caplog.records if rec.levelno == logging.ERROR]
    assert len(messages) == 0
    caplog.clear()

    server.add_handler('on_register_report', on_register_report_returning_string)
    await client.register_reports(client.reports)
    assert len(client.report_requests) == 0
    assert "Your on_register_report handler must return a tuple or None; it returned 'Hello There' (str)." in caplog.messages
    caplog.clear()

    server.add_handler('on_register_report', on_register_report_returning_uncallable_first_element)
    await client.register_reports(client.reports)
    assert len(client.report_requests) == 0
    assert(f"Your on_register_report handler did not return the correct tuple. "
           "It should return a (callback, sampling_interval) or "
           "(callback, sampling_interval, reporting_interval) tuple, where "
           "the callback is a callable function or coroutine, and "
           "sampling_interval and reporting_interval are of type datetime.timedelta. "
           "It returned: '('Hello', 'There')'. The first element was not callable.") in caplog.messages
    caplog.clear()

    server.add_handler('on_register_report', on_register_report_returning_non_datetime_second_element)
    await client.register_reports(client.reports)
    assert len(client.report_requests) == 0
    assert (f"Your on_register_report handler did not return the correct tuple. "
            "It should return a (callback, sampling_interval) or "
            "(callback, sampling_interval, reporting_interval) tuple, where "
            "sampling_interval and reporting_interval are of type datetime.timedelta. "
            f"It returned: '{(report_callback, 'Hello There')}'. The second element was not of type timedelta.") in caplog.messages
    caplog.clear()

    server.add_handler('on_register_report', on_register_report_returning_non_datetime_third_element)
    await client.register_reports(client.reports)
    assert len(client.report_requests) == 0
    assert ("Your on_register_report handler did not return the correct tuple. "
            "It should return a (callback, sampling_interval) or "
            "(callback, sampling_interval, reporting_interval) tuple, where "
            "sampling_interval and reporting_interval are of type datetime.timedelta. "
            f"It returned: '{(report_callback, timedelta(minutes=10), 'Hello There')}'. The third element was not of type timedelta.") in caplog.messages
    caplog.clear()

    server.add_handler('on_register_report', on_register_report_returning_too_long_tuple)
    await client.register_reports(client.reports)
    assert len(client.report_requests) == 0
    assert ("Your on_register_report handler returned a tuple of the wrong length. "
            "It should be 2 or 3. "
            f"It returned: '{(report_callback, timedelta(minutes=10), timedelta(minutes=10), 'Hello')}'.") in caplog.messages
    caplog.clear()

    server.add_handler('on_register_report', on_register_report_full_returning_string)
    await client.register_reports(client.reports)
    assert len(client.report_requests) == 0
    assert "Your on_register_report handler must return a list of tuples or None; it returned 'Hello There' (str)." in caplog.messages
    caplog.clear()

    server.add_handler('on_register_report', on_register_report_full_returning_list_of_strings)
    await client.register_reports(client.reports)
    assert len(client.report_requests) == 0
    assert ("Your on_register_report handler must return a list of tuples or None; "
            f"The first item from the list was 'Hello' (str).") in caplog.messages
    caplog.clear()

    server.add_handler('on_register_report', on_register_report_full_returning_list_of_tuples_of_wrong_length)
    await client.register_reports(client.reports)
    assert len(client.report_requests) == 0
    assert ("Your on_register_report handler returned tuples of the wrong length. "
            "It should be 3 or 4. It returned: '('Hello', 'There')'.") in caplog.messages
    caplog.clear()

    server.add_handler('on_register_report', on_register_report_full_returning_list_of_tuples_with_no_callable)
    await client.register_reports(client.reports)
    assert len(client.report_requests) == 0
    assert ("Your on_register_report handler did not return the correct tuple. "
            "It should return a list of (r_id, callback, sampling_interval) or "
            "(r_id, callback, sampling_interval, reporting_interval) tuples, "
            "where the r_id is a string, callback is a callable function or "
            "coroutine, and sampling_interval and reporting_interval are of "
            "type datetime.timedelta. It returned: '('Hello', 'There', 'World')'. "
            "The second element was not callable.") in caplog.messages
    caplog.clear()

    server.add_handler('on_register_report', on_register_report_full_returning_list_of_tuples_with_no_timedelta)
    await client.register_reports(client.reports)
    assert len(client.report_requests) == 0
    assert ("Your on_register_report handler returned tuples of the wrong length. "
            f"It should be 3 or 4. It returned: '({report_callback}, 'Hello There')'.") in caplog.messages

    await server.stop()
    await client.stop()