def test_add_report_with_invalid_callback_signature(): client = OpenADRClient(ven_name='myven', vtn_url='http://localhost') with pytest.raises(TypeError): client.add_report(callback=wrong_sig, data_collection_mode='full', resource_id='myresource1', measurement='voltage')
async def test_openadr_error(start_server): client = OpenADRClient( vtn_url=f"http://localhost:{SERVER_PORT}/OpenADR2/Simple/2.0b", ven_name=VEN_NAME) client.on_event = _client_on_event await client.run() await client.client_session.close()
async def test_client_event_cleanup(): 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() client = OpenADRClient( ven_name='ven123', vtn_url='http://localhost:8080/OpenADR2/Simple/2.0b') client.add_handler('on_event', on_event_opt_in) await client.run() await asyncio.sleep(0.5) assert len(client.received_events) == 1 await asyncio.sleep(0.5) await client._event_cleanup() assert len(client.received_events) == 0 await server.stop() await client.stop()
def test_invalid_scale(): client = OpenADRClient(ven_name='myven', vtn_url='http://localhost') with pytest.raises(ValueError): client.add_report(callback=print, resource_id='myresource', measurement='voltage', scale='non_existant')
def test_add_report_invalid_description(caplog): client = OpenADRClient(ven_name='myven', vtn_url='http://localhost:8080/OpenADR2/Simple/2.0b') with pytest.raises(ValueError): client.add_report(callback=print, report_specifier_id='myreport', measurement={'name': 'voltage', 'description': 'SomethingWrong', 'unit': 'V'}, resource_id='Device001', sampling_rate=timedelta(seconds=10))
def test_add_report_invalid_unit(caplog): client = OpenADRClient(ven_name='myven', vtn_url='http://localhost:8080/OpenADR2/Simple/2.0b') client.add_report(callback=print, report_specifier_id='myreport', measurement='voltage', resource_id='Device001', sampling_rate=timedelta(seconds=10), unit='A') assert caplog.record_tuples == [("openleadr", logging.WARNING, f"The supplied unit A for measurement voltage will be ignored, V will be used instead. Allowed units for this measurement are: V")]
async def test_signature_error(start_server_with_signatures): client = OpenADRClient( vtn_url=f"http://localhost:{SERVER_PORT}/OpenADR2/Simple/2.0b", ven_name=VEN_NAME, vtn_fingerprint="INVALID") client.on_event = _client_on_event await client.run() await asyncio.sleep(0) await client.client_session.close()
async def test_incremental_reports(): loop = asyncio.get_event_loop() client = OpenADRClient( ven_name='myven', vtn_url='http://localhost:8080/OpenADR2/Simple/2.0b') collect_futures = [loop.create_future() for i in range(2)] client.add_report(callback=partial(collect_data_multi, futures=collect_futures), report_specifier_id='myhistory', measurement='voltage', resource_id='mydevice', sampling_rate=timedelta(seconds=2)) server = OpenADRServer(vtn_id='myvtn') register_report_future = loop.create_future() update_report_future = loop.create_future() server.add_handler( 'on_register_report', partial(on_register_report, bundling=2, futures=[register_report_future], receive_futures=[update_report_future])) party_future = loop.create_future() server.add_handler( 'on_create_party_registration', partial(on_create_party_registration, future=party_future)) loop.create_task(server.run_async()) await asyncio.sleep(1) await client.run() print("Awaiting party future") await party_future print("Awaiting register report future") await register_report_future print("Awaiting first data collection future... ", end="") await collect_futures[0] print("check") await asyncio.sleep(1) print("Checking that the report was not yet sent... ", end="") assert update_report_future.done() is False print("check") print("Awaiting data collection second future... ", end="") await collect_futures[1] print("check") print("Awaiting report update future") result = await update_report_future assert len(result) == 2 await server.stop() await client.stop() await asyncio.sleep(0)
def test_add_report_invalid_scale(): client = OpenADRClient(ven_name='myven', vtn_url='http://localhost:8080/OpenADR2/Simple/2.0b') with pytest.raises(ValueError): client.add_report(callback=print, report_specifier_id='myreport', measurement='power_real', resource_id='Device001', sampling_rate=timedelta(seconds=10), unit='W', scale='xxx')
async def test_raw_event(): now = datetime.datetime.now(datetime.timezone.utc) server = OpenADRServer(vtn_id='myvtn') server.add_handler('on_create_party_registration', on_create_party_registration) event = 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='ven123')]) loop = asyncio.get_event_loop() event_callback_future = loop.create_future() server.add_raw_event(ven_id='ven123', event=event, callback=partial(event_callback, future=event_callback_future)) on_event_future = loop.create_future() client = OpenADRClient( ven_name='myven', vtn_url='http://localhost:8080/OpenADR2/Simple/2.0b') client.add_handler('on_event', partial(on_event_opt_in, future=on_event_future)) await server.run_async() await client.run() event = await on_event_future assert len(event['event_signals']) == 2 result = await event_callback_future assert result == 'optIn' await client.stop() await server.stop()
async def test_update_report_data_collection_mode_full(): loop = asyncio.get_event_loop() client = OpenADRClient( ven_name='myven', vtn_url='http://localhost:8080/OpenADR2/Simple/2.0b') data_collection_future = loop.create_future() client.add_report(callback=partial(collect_data_history, futures=[data_collection_future]), resource_id='Device001', measurement='power_real', data_collection_mode='full', sampling_rate=timedelta(seconds=1), unit='W') report_register_future = loop.create_future() report_received_future = loop.create_future() party_registration_future = loop.create_future() server = OpenADRServer(vtn_id='myvtn') server.add_handler( 'on_create_party_registration', partial(on_create_party_registration, future=party_registration_future)) server.add_handler( 'on_register_report', partial(on_register_report, bundling=2, futures=[report_register_future], receive_futures=[report_received_future])) await server.run_async() await asyncio.sleep(0.1) print(f"The time is now {datetime.now()}") t = time.time() wait_for = int(t / 2) * 2 + 2 - t await asyncio.sleep(wait_for) print(f"The time is now {datetime.now()}, running client") await client.run() await party_registration_future await report_register_future await asyncio.sleep(1) print( f"The time is now {datetime.now()}, checking if report was triggered") assert data_collection_future.done() is False print("Waiting for the data collection to occur") await data_collection_future print("Waiting for the report to be received") await report_received_future print("Done") await server.stop() await client.stop()
def test_add_report_non_standard_measurement(): client = OpenADRClient(ven_name='myven', vtn_url='http://localhost:8080/OpenADR2/Simple/2.0b') client.add_report(callback=print, report_specifier_id='myreport', measurement='rainbows', resource_id='Device001', sampling_rate=timedelta(seconds=10), unit='A') assert len(client.reports) == 1 assert client.reports[0].report_descriptions[0].measurement.name == 'customUnit' assert client.reports[0].report_descriptions[0].measurement.description == 'rainbows'
def test_add_report_invalid_description(caplog): client = OpenADRClient( ven_name='myven', vtn_url='http://localhost:8080/OpenADR2/Simple/2.0b') client.add_report(callback=print, report_specifier_id='myreport', measurement={ 'name': 'voltage', 'description': 'SomethingWrong', 'unit': 'V' }, resource_id='mydevice', sampling_rate=timedelta(seconds=10)) msg = create_message('oadrRegisterReport', reports=client.reports)
async def test_report_registration(): """ Test the registration of two reports with two r_ids each. """ # Create a server logger = logging.getLogger('openleadr') logger.setLevel(logging.DEBUG) server = OpenADRServer(vtn_id='testvtn') server.add_handler('on_register_report', on_register_report) server.add_handler('on_create_party_registration', on_create_party_registration) # Create a client client = OpenADRClient( ven_name='myven', vtn_url='http://localhost:8080/OpenADR2/Simple/2.0b', ) # Add 4 reports client.add_report(callback=collect_data, report_specifier_id='CurrentReport', resource_id='Device001', measurement='current', unit='A') client.add_report(callback=collect_data, report_specifier_id='CurrentReport', resource_id='Device002', measurement='current', unit='A') client.add_report(callback=collect_data, report_specifier_id='VoltageReport', resource_id='Device001', measurement='voltage', unit='V') client.add_report(callback=collect_data, report_specifier_id='VoltageReport', resource_id='Device002', measurement='voltage', unit='V') asyncio.create_task(server.run_async()) await asyncio.sleep(1) # Register the client await client.create_party_registration() # Register the reports await client.register_reports(client.reports) assert len(client.report_requests) == 2 assert len(server.services['report_service'].report_callbacks) == 4 await client.stop() await server.stop()
def test_replay_protect_repeated_message(caplog): client = OpenADRClient( ven_name='myven', vtn_url=f'https://localhost:{SERVER_PORT}/OpenADR2/Simple/2.0b', cert=VEN_CERT, key=VEN_KEY, vtn_fingerprint=VTN_FINGERPRINT) message = client._create_message('oadrPoll', ven_id='ven123') tree = etree.fromstring(message.encode('utf-8')) messaging._verify_replay_protect(tree) with pytest.raises(ValueError) as err: messaging._verify_replay_protect(tree) assert str(err.value ) == 'This combination of timestamp and nonce was already used.'
def test_replay_protect_message_too_old(caplog): client = OpenADRClient( ven_name='myven', vtn_url=f'https://localhost:{SERVER_PORT}/OpenADR2/Simple/2.0b', cert=VEN_CERT, key=VEN_KEY, vtn_fingerprint=VTN_FINGERPRINT) _temp = messaging.REPLAY_PROTECT_MAX_TIME_DELTA messaging.REPLAY_PROTECT_MAX_TIME_DELTA = timedelta(seconds=0) message = client._create_message('oadrPoll', ven_id='ven123') tree = etree.fromstring(message.encode('utf-8')) with pytest.raises(ValueError) as err: messaging._verify_replay_protect(tree) assert str(err.value) == 'The message was signed too long ago.' messaging.REPLAY_PROTECT_MAX_TIME_DELTA = _temp
def test_replay_protect_missing_nonce(caplog): client = OpenADRClient( ven_name='myven', vtn_url=f'https://localhost:{SERVER_PORT}/OpenADR2/Simple/2.0b', cert=VEN_CERT, key=VEN_KEY, vtn_fingerprint=VTN_FINGERPRINT) message = client._create_message('oadrPoll', ven_id='ven123') message = re.sub('<dsp:nonce>.*?</dsp:nonce>', '', message) tree = etree.fromstring(message.encode('utf-8')) with pytest.raises(ValueError) as err: messaging._verify_replay_protect(tree) assert str( err.value ) == "Missing 'nonce' element in ReplayProtect in incoming message."
async def test_request_event(): loop = asyncio.get_event_loop() client = OpenADRClient( ven_name='myven', vtn_url='http://localhost:8080/OpenADR2/Simple/2.0b') server = OpenADRServer(vtn_id='myvtn', requested_poll_freq=datetime.timedelta(seconds=1)) server.add_handler('on_create_party_registration', on_create_party_registration) event_id = server.add_event( ven_id='ven123', signal_name='simple', signal_type='level', intervals=[{ 'dtstart': datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(seconds=4), 'duration': datetime.timedelta(seconds=2), 'signal_payload': 1 }], ramp_up_period=datetime.timedelta(seconds=2), callback=partial(event_callback)) assert server.events['ven123'][0].event_descriptor.event_status == 'far' await server.run_async() await client.create_party_registration() message_type, message_payload = await client.request_event() assert message_type == 'oadrDistributeEvent' message_type, message_payload = await client.request_event() assert message_type == 'oadrDistributeEvent' await client.stop() await server.stop()
async def test_ssl_certificates_wrong_fingerprint(caplog): loop = asyncio.get_event_loop() registration_future = loop.create_future() server = OpenADRServer(vtn_id='myvtn', http_cert=VTN_CERT, http_key=VTN_KEY, http_ca_file=CA_CERT, cert=VTN_CERT, key=VTN_KEY, fingerprint_lookup=lookup_fingerprint) server.add_handler('on_create_party_registration', partial(on_create_party_registration, future=registration_future)) await server.run_async() #await asyncio.sleep(1) # Run the client client = OpenADRClient(ven_name='myven', vtn_url='https://localhost:8080/OpenADR2/Simple/2.0b', cert=VEN_CERT, key=VEN_KEY, ca_file=CA_CERT, vtn_fingerprint='00:11:22:33:44:55:66:77:88:99') await client.run() # Wait for the registration to be triggered result = await asyncio.wait_for(registration_future, 1.0) assert client.registration_id is None assert ("The certificate fingerprint was incorrect. Expected: 00:11:22:33:44:55:66:77:88:99; " "Received: 39:0F:7F:45:84:D6:24:49:FE:B7. Ignoring message.") in [rec.message for rec in caplog.records] await client.stop() await server.stop()
async def test_ssl_certificates(disable_signature): loop = asyncio.get_event_loop() registration_future = loop.create_future() server = OpenADRServer(vtn_id='myvtn', http_cert=VTN_CERT, http_key=VTN_KEY, http_ca_file=CA_CERT, cert=VTN_CERT, key=VTN_KEY, fingerprint_lookup=lookup_fingerprint) server.add_handler('on_create_party_registration', partial(on_create_party_registration, future=registration_future)) await server.run_async() #await asyncio.sleep(1) # Run the client client = OpenADRClient(ven_name='myven', vtn_url='https://localhost:8080/OpenADR2/Simple/2.0b', cert=VEN_CERT, key=VEN_KEY, ca_file=CA_CERT, vtn_fingerprint=vtn_fingerprint, disable_signature=disable_signature) await client.run() # Wait for the registration to be triggered result = await asyncio.wait_for(registration_future, 1.0) assert client.registration_id == 'reg5678' await client.stop() await server.stop()
async def test_ssl_certificates_wrong_cert(): loop = asyncio.get_event_loop() registration_future = loop.create_future() server = OpenADRServer(vtn_id='myvtn', http_cert=VTN_CERT, http_key=VTN_KEY, http_ca_file=CA_CERT, cert=VTN_CERT, key=VTN_KEY, fingerprint_lookup=lookup_fingerprint) server.add_handler('on_create_party_registration', partial(on_create_party_registration, future=registration_future)) await server.run_async() #await asyncio.sleep(1) # Run the client client = OpenADRClient(ven_name='myven', vtn_url='https://localhost:8080/OpenADR2/Simple/2.0b', cert=VTN_CERT, key=VTN_KEY, ca_file=CA_CERT, vtn_fingerprint=vtn_fingerprint) await client.run() # Wait for the registration to be triggered with pytest.raises(asyncio.TimeoutError): await asyncio.wait_for(registration_future, timeout=0.5) assert client.registration_id is None await client.stop() await server.stop() await asyncio.sleep(0)
async def test_register_historic_report(): client = OpenADRClient(ven_name='myven', vtn_url='http://localhost:8080/OpenADR2/Simple/2.0b') client.add_report(report_name='HISTORY_USAGE', callback=get_historic_data, measurement='voltage', resource_id='Device001', sampling_rate=timedelta(seconds=1)) server = OpenADRServer(vtn_id='myvtn') server.add_handler('on_create_party_registration', on_create_party_registration) # server.add_handler('on_register_report', on_register_report_historic) await server.run() await client.run() assert len(server.registered_reports) == 1 await client.stop() await server.stop()
async def test_create_party_registration(start_server): client = OpenADRClient( ven_name=VEN_NAME, vtn_url=f"http://localhost:{SERVER_PORT}/OpenADR2/Simple/2.0b") response_type, response_payload = await client.create_party_registration() assert response_type == 'oadrCreatedPartyRegistration' assert response_payload['ven_id'] == VEN_ID
async def test_client_exception_event_handler(caplog): caplog.set_level(logging.WARNING) enable_default_logging() logger = logging.getLogger('openleadr') logger.setLevel(logging.DEBUG) client = OpenADRClient( ven_name='myven', vtn_url='http://localhost:8080/OpenADR2/Simple/2.0b') client.add_handler('on_event', broken_on_event) server = OpenADRServer(vtn_id='myvtn', requested_poll_freq=timedelta(seconds=1)) server.add_handler('on_create_party_registration', on_create_party_registration) print("Running server") await server.run_async() await asyncio.sleep(0.1) print("Running client") await client.run() event_confirm_future = asyncio.get_event_loop().create_future() print("Adding event") server.add_event(ven_id='venid', signal_name='simple', signal_type='level', intervals=[{ 'dtstart': datetime.now(), 'duration': timedelta(seconds=10), 'signal_payload': 1.1 }], target={'ven_id': 'venid'}, callback=partial(on_event_accepted, future=event_confirm_future)) print("Waiting for a response to the event") result = await event_confirm_future assert result == 'optOut' err = KeyError("BOOM") assert ( "Your on_event handler encountered an error. Will Opt Out of the event. " f"The error was {err.__class__.__name__}: {str(err)}") in [ rec.message for rec in caplog.records ] await client.stop() await server.stop() await asyncio.sleep(0)
async def test_client_good_event_handler(caplog): caplog.set_level(logging.WARNING) logger = logging.getLogger('openleadr') logger.setLevel(logging.DEBUG) client = OpenADRClient( ven_name='myven', vtn_url='http://localhost:8080/OpenADR2/Simple/2.0b') client.add_handler('on_event', good_on_event) server = OpenADRServer(vtn_id='myvtn', requested_poll_freq=timedelta(seconds=1)) server.add_handler('on_create_party_registration', on_create_party_registration) caplog.clear() print("Running server") await server.run_async() # await asyncio.sleep(0.1) print("Running client") await client.run() event_confirm_future = asyncio.get_event_loop().create_future() print("Adding event") server.add_event(ven_id='venid', event_id='test_client_good_event_handler', signal_name='simple', signal_type='level', intervals=[{ 'dtstart': datetime.now(timezone.utc), 'duration': timedelta(seconds=1), 'signal_payload': 1.1 }], target={'ven_id': 'venid'}, callback=partial(on_event_accepted, future=event_confirm_future)) print("Waiting for a response to the event") result = await event_confirm_future assert result == 'optIn' print("-" * 80) print("THE CAPLOG RECORDS ARE:") print(caplog.records) print("-" * 80) assert len(caplog.records) == 0 await client.stop() await server.stop() await asyncio.gather(*[t for t in asyncio.all_tasks()][1:])
async def test_client_warning_no_update_event_handler(caplog): caplog.set_level(logging.WARNING) logger = logging.getLogger('openleadr') logger.setLevel(logging.DEBUG) server = OpenADRServer(vtn_id='myvtn', requested_poll_freq=timedelta(seconds=1)) server.add_handler('on_create_party_registration', on_create_party_registration) event_accepted_future = asyncio.get_event_loop().create_future() server.add_event(ven_id='venid', event_id='test_client_warning_no_update_event_handler', signal_name='simple', signal_type='level', intervals=[{ 'dtstart': datetime.now(timezone.utc), 'duration': timedelta(seconds=1), 'signal_payload': 1.1 }], target={'ven_id': 'venid'}, callback=event_accepted_future) client = OpenADRClient( ven_name='myven', vtn_url='http://localhost:8080/OpenADR2/Simple/2.0b') client.add_handler('on_event', good_on_event) print("Starting server") await server.run() await client.run() print("Waiting for first event to be accepted...") await event_accepted_future # Manually update the event server.events['venid'][0].event_descriptor.modification_number = 1 server.events_updated['venid'] = True await asyncio.sleep(1) assert ( "An Event was updated, but you don't have an on_updated_event handler configured. " "You should implement your own on_update_event handler. This handler receives " "an Event dict and should return either 'optIn' or 'optOut' based on your " "choice. Will re-use the previous opt status for this event_id for now" ) in [record.msg for record in caplog.records] await client.stop() await server.stop() await asyncio.gather(*[t for t in asyncio.all_tasks()][1:])
async def test_client_faulty_event_handler(caplog): caplog.set_level(logging.WARNING) logger = logging.getLogger('openleadr') logger.setLevel(logging.DEBUG) client = OpenADRClient( ven_name='myven', vtn_url='http://localhost:8080/OpenADR2/Simple/2.0b') client.add_handler('on_event', faulty_on_event) server = OpenADRServer(vtn_id='myvtn', requested_poll_freq=timedelta(seconds=1)) server.add_handler('on_create_party_registration', on_create_party_registration) print("Running server") await server.run_async() # await asyncio.sleep(0.1) print("Running client") await client.run() event_confirm_future = asyncio.get_event_loop().create_future() print("Adding event") server.add_event(ven_id='venid', event_id='test_client_faulty_event_handler', signal_name='simple', signal_type='level', intervals=[{ 'dtstart': datetime.now(timezone.utc), 'duration': timedelta(seconds=1), 'signal_payload': 1.1 }], target={'ven_id': 'venid'}, callback=partial(on_event_accepted, future=event_confirm_future)) print("Waiting for a response to the event") result = await event_confirm_future assert result == 'optOut' assert ( "Your on_event or on_update_event handler must return 'optIn' or 'optOut'; " f"you supplied {None}. Please fix your on_event handler.") in [ rec.message for rec in caplog.records ] await client.stop() await server.stop() await asyncio.gather(*[t for t in asyncio.all_tasks()][1:])
async def test_wrong_endpoint(start_server, caplog): message = messaging.create_message("oadrQueryRegistration", request_id='req1234') client = OpenADRClient( ven_name='myven', vtn_url=f'http://localhost:{SERVER_PORT}/OpenADR2/Simple/2.0b') response_type, response_payload = await client._perform_request( 'OadrPoll', message) assert response_type == 'oadrResponse' assert response_payload['response']['response_code'] == 459
async def test_throw_protocol_error(caplog): server = OpenADRServer(vtn_id=VTN_ID, http_port=SERVER_PORT) server.add_handler('on_create_party_registration', protocol_error_handler) await server.run_async() client = OpenADRClient( ven_name='myven', vtn_url=f'http://localhost:{SERVER_PORT}/OpenADR2/Simple/2.0b') await client.run() #await asyncio.sleep(0.5) await client.stop() await server.stop() assert 'We got a non-OK OpenADR response from the server: 450: OUT OF SEQUENCE' in caplog.messages
async def test_invalid_signature_error(start_server_with_signatures, caplog): client = OpenADRClient( ven_name='myven', vtn_url=f'https://localhost:{SERVER_PORT}/OpenADR2/Simple/2.0b', cert=VEN_CERT, key=VEN_KEY, vtn_fingerprint=VTN_FINGERPRINT) message = client._create_message('oadrPoll', ven_id='ven123') fake_sig = b64encode("HelloThere".encode('utf-8')).decode('utf-8') message = re.sub(r'<ds:SignatureValue>.*?</ds:SignatureValue>', f'<ds:SignatureValue>{fake_sig}</ds:SignatureValue>', message) result = await client._perform_request('OadrPoll', message) assert result == (None, {}) logs = [rec.message for rec in caplog.records] for log in logs: if log.startswith("Non-OK status 403 when performing a request"): assert "Invalid Signature" in log break else: assert False